Dynamically Control the WhatId reference field popup

I am trying to dynamically control the table columns in a WhatId reference field popup. 

With the help from this post I was able to limit my WhatId field to the Account, Campaign, and Opportunity objects, but I need to go one step further and dynamically display table columns in the popup based on the selected object. 

I was able to “sort of” dynamically render the table columns with the below script, but it requires a user to enter text in the field, click on a selection and then press the lookup icon. If a users tries to switch the object and press the lookup icon either it will error out based on the prior selection or it won’t switch. Any help is appreciated!

params = arguments[0], model = params.model, row = params.row, $ = skuid.$; var whatId = row.WhatId; var refString = String(whatId); var refLength = refString.substring(0, 3); switch ( refLength) { case "001": field.options.returnFields = [ {id: 'Id', showInSearchDialog: false}, {id: 'Name', showInSearchDialog: true}, ]; break; case "701": field.options.returnFields = [ {id: 'Id', showInSearchDialog: false}, {id: 'Id', showInSearchDialog: true}, ]; break; case "006": field.options.returnFields = [ {id: 'Id', showInSearchDialog: false}, {id: 'Name', showInSearchDialog: true}, {id: 'StageName', showInSearchDialog: true}, {id: 'CloseDate', showInSearchDialog: true}, ]; break; } 

Josef,

Since you have a limited number of objects that you want to dynamically control for, you could use Reference UI Only fields to display a lookup tied to a single object. Here is a sample page that demonstrates this.

I have used a UI Only model with a picklist field to control what lookup field shows in a table or in a field editor. I added model actions to the Task model to set the WhatId field based on the selection in the Reference UI Only field. I think this will meet your needs.

Thanks,

Bill

row.updated CaseLookup row.updated OpportunityLookup New {{Model.label}} {{Model.labelPlural}}

Hey Bill,

Thanks for the reply! While your solution is very helpful and useful (and currently what I’m leveraging on a field editor), it doesn’t quite meet my requirements because i’m working with table.

I wouldn’t want to add additional columns to my table.

Josef,

I was thinking that you would only show 1 type of Related To object in a table.  What I proposed won’t work since you have different types per row.

Could you restate what problem you are trying to solve or what use case you want to enable?

Thanks,

Bill

The Related To field is currently displaying Account, Opportunity, or Campaign records based on user choice.

When a user clicks the magnifying glass icon for Related To = ‘Account’ then the Popup that follows should display Account specific fields. Same when a user clicks the magnifying glass icon for Campaigns, the Campaign Popup that follows should display Campaign specific fields and so on for Opportunities. 


Josef,

I see now.  You want to be able to show specific object-related fields when you click the magnifying glass.  I think because the Related To field is polymorphic, Salesforce only supports retrieving certain fields from each object.  I am pretty sure that there is now way to configure the popup ‘search window’ with specific fields.

I think you would have to do this as a custom field render, then you can control what happens when the user clicks the magnifying glass.  If the requirement doesn’t include inline changes, you should be able to do a declarative solution using a row action.

Thanks,

Bill

I currently have a custom field render on the field, but my snippet is not 100%. The snippet in the description is accurately changing the popup fields ONLY when a user first searches for a particular record before clicking the magnifying glass. If a user searches for a record first then my snippet has the context via the ID prefix. 

I need help detecting the change of the related to object prior to searching for a record. Similar to how skuid creates a temporary model when you switch the related to object. 

Hi Josef, I would recommend experimenting with the Search Component. It’s highly configurable - you can set up multiple objects to search, and different search fields for each one, as well as different display templates in the search results list, and different fields in the table that displays the results. You could set up a return action for each object that sets the WhatId upon clicking on the result. I think it was designed for use cases like yours, from what I understand about your goal. 

hey Mark, I can see using the Search component and I may resort to that, but I want to explore Josef’s idea more, it seems promising to me. I wrote it up in a new thread, because I’m more interested in using a snippet to control the search and display template of a polymorphic reference field:

http://community.skuid.com/skuid/topics/use-javascript-to-control-the-display-and-search-templates-

Hi Tim,

It doesn’t look like that link is working. Could there have been a problem when posting it? I believe late last week, the Community may have had some intermittent issues. Let me know if you are able to link to the post, or if you end up writing another one, and I’d be happy to look at your question. 

Hmm … oh well. Yeah after I posted it, the community site was having some issues. My post shows up in search results, but there’s nothing behind it. If it can’t be recovered based on this clue, I’ll try to find time to rewrite it.


Hey Tim, I know the struggle of looking for answers so heres the end product. Use this as your “Related to” field’s snippet:

var targetObjects = ['Account', 'Opportunity', 'Campaign'];
var renderAsPicklist = false;
field = arguments[0];
var value = skuid.utils.decodeHTML(arguments[1]),
  metadata = field.metadata,
  $ = skuid.$;
var params = arguments[0], model = params.model,
row = params.row,
 $ = skuid.$;

var updateFieldData = function(field, refLength) {
  switch ( refLength) {
    case "001": // Account
      field.options.returnFields = [
      {id: 'Id', showInSearchDialog: false},
      {id: 'Name', showInSearchDialog: true},
      {id: 'Type', showInSearchDialog: true},
      {id: 'Owner.Name', showInSearchDialog: true},
    ];
    field.options.searchTemplate = "{{Name}} - Type: {{Type}} - Owner: {{Owner.Name}}";
    break;
    case "701": // Campaign
     field.options.returnFields = [
      {id: 'Id', showInSearchDialog: false},
      {id: 'Name', showInSearchDialog: true},
      {id: 'Campaign_Channel__c', showInSearchDialog: true},
      {id: 'Type', showInSearchDialog: true},
      {id: 'Period__c', showInSearchDialog: true},
    ];
    field.options.searchTemplate = "{{Name}} - Channel: {{Campaign_Channel__c}} - Period: {{Period__c}}";
    break;
    case "006": // Oppty
      field.options.returnFields = [
      {id: 'Id', showInSearchDialog: false},
      {id: 'Name', showInSearchDialog: true},
      {id: 'StageName', showInSearchDialog: true},
      {id: 'CloseDate', showInSearchDialog: true},
      {id: 'Industry__c', showInSearchDialog: true},
      {id: 'Owner.Name', showInSearchDialog: true},
    ];
    field.options.searchTemplate = "{{Name}} - Type: {{StageName}} - Industry: {{Industry__c}}";
    break;
  } 
};

if (field.mode == 'edit') {
  // Limit the set of target objects
  var targets = [],
   uniqueTargets = {};
  $.each(metadata.referenceTo,function(i,r) {
   if (($.inArray(r.objectName,targetObjects) != -1) && (!uniqueTargets[r.objectName])) {
     targets.push(r);
     uniqueTargets[r.objectName] = 1;
     if (targets.length == targetObjects.length) return false;
    }
  });
  if (targets.length) {
   // Make this field render as a picklist?
   if (renderAsPicklist) field.options.type = 'REFPICK';
   // Override the current referenceTo
   metadata.referenceTo.length = 0;
   metadata.ref = $.map(targets,function(targ){return targ.objectName;}).join();
   metadata.referenceTo = targets;
  }
}

  skuid.ui.getFieldRenderer(field)[field.mode]( field, value );
  //skuid.ui.fieldRenderers[metadata.displaytype][field.mode](field,value);

var params = arguments[0], 
  model = params.model,
  row = params.row,
  $ = skuid.$;

var whatId = row.WhatId;

var refString = String(whatId);
var refLength = refString.substring(0, 3);
if ( refLength === 'und') refLength = "001";//default to account

$(field.element).find("select").bind("change", function(e) {
 var val = $( "select option:selected" ).text();
 if ( val.startsWith("Opportunity")) {
   updateFieldData(field,"006");
 } else if ( val.startsWith("Account")) {
   updateFieldData(field,"001");
 } else if ( val.startsWith("Campaign")) {
   updateFieldData(field,"701");
 }
 
});

updateFieldData(field, refLength);

Joe, thank you for sharing this and contributing to the Community. 

Tim, is this helpful in your research?

Maybe! I haven’t had a chance to look at it yet. Joe, I greatly appreciate the code share, and I will let you know how it goes.

Thanks again for sharing the code, Josef. I may misunderstand, but I am still unable to modify the WhatID field.options.searchTemplate parameter. I’ve tried running a script both from a field renderer, and from a model action that is initiated when the WhatID field is updated (which includes when someone changes the parent object picklist).

I’ve settled for restricting my targetObjects array to objects that have Name fields, which are easier to identify by search. One problem I have is that objects with autonumber IDs appear in the search layout as “C-0001”, “C-0002” and so on. I removed those objects from my WhatID field to avoid frustrating my end users with unclear search results.

The drawback of course is that my Named objects will only return results based on search terms in the Name field, but I think I can live with that for now.

I may take another crack at this some day. If someone else has a great way to modify the searchTemplate of the polymorphic WhatID field, I’m all ears.

I don’t understand what you mean by unable to modify the field.options.searchTemplate. Can you share the modifications you’ve made to the code? 

Change the fields for field.options.searchTemplate in the case statements will modify what’s displayed to the end user. 

I figured out my problem… I have more than one picklist on the form, and the WhatId is not first. So when using jquery to run the function when the selector is changed, I had to use includes() instead of startsWith().

It is working now. My code is below.

Now I have one quibble that I’d like to work out. When I first select my WhatId object type, and begin typing to search, it displays the searchTemplate correctly, but it does not search on searchTemplate fields other than Name. If I choose one of the search results, then repeat my first search term, it successfully searches on searchTemplate fields other than Name.

Step 1: No results when searching on a field other than Name


Step 2: Search on Name, click any result

Step 3: Repeat the first search, now there are results

var $ = skuid.$,
    targetObjects = ['Campaign', 'Opportunity', 'Account', 'Program\_Cohort\_\_c', 'Proposal\_\_c', 'Team\_\_c'], // Define the objects made available in the selector.
    field = arguments[0], 
    value = skuid.utils.decodeHTML(arguments[1]), 
    metadata = field.metadata, 
    model = field.model,
    row = field.row,
    whatId = row.WhatId,
    whatString = String(whatId),
    whatPrefix = whatString.substring(0,3),
    renderAsPicklist = false; // if set to true, WhatId lookup field becomes a picklist. Not useful for objects with large number of search results.
    
var updateFieldData = function(field, whatPrefix) {
    
    // this function controls which fields are searched and made visible in the selector popup.
    // [https://community.skuid.com/skuid/topics/use-javascript-to-control-the-display-and-search-templates-...](https://community.skuid.com/skuid/topics/use-javascript-to-control-the-display-and-search-templates-of-a-polymorphic-whatid-field?rfm=1 "Link httpscommunityskuidcomskuidtopicsuse-javascript-to-control-the-display-and-search-templates-of-a-polymorphic-whatid-fieldrfm1")
    switch ( whatPrefix ) {
        
        case "701":     // Campaign
            field.options.returnFields = [
                {id: 'Id', showInSearchDialog: false},
                {id: 'Name', showInSearchDialog: true},
                {id: 'Program\_\_c', showInSearchDialog: true},
                {id: 'StartDate', showInSearchDialog: true},
                {id: 'EndDate', showInSearchDialog: true},
            ];
            field.options.searchTemplate = "{{Name}}, Program: {{Program\_\_c}}, {{StartDate}} - {{EndDate}}";
            break;
            
        case "006":     // Opportunity
            field.options.returnFields = [
                {id: 'Id', showInSearchDialog: false},
                {id: 'Name', showInSearchDialog: true},  
                {id: 'StageName', showInSearchDialog: true},  
            ];
            field.options.searchTemplate = "{{Name}}, Stage: {{StageName}}";
            break;
            
        case "001":     // Account aka Organization
            field.options.returnFields = [
                {id: 'Id', showInSearchDialog: false},
                {id: 'Name', showInSearchDialog: true},
                {id: 'Organization\_Alias\_Name\_\_c', showInSearchDialog: true},
            ];
            field.options.searchTemplate = "{{Name}}, Alias: {{Organization\_Alias\_Name\_\_c}}";
            break;
        
        case "a2C":     // Program Cohort
            field.options.returnFields = [
                {id: 'Id', showInSearchDialog: false},
                {id: 'Name', showInSearchDialog: true},
                {id: 'Program\_Start\_Date\_\_c', showInSearchDialog: true},
                {id: 'Program\_End\_Date\_\_c', showInSearchDialog: true},
            ];
            field.options.searchTemplate = "{{Name}}, {{Program\_Start\_Date\_\_c}} - {{Program\_End\_Date\_\_c}}";
            break;
        
        case "a2m":     // Proposal
            field.options.returnFields = [
                {id: 'Id', showInSearchDialog: false},
                {id: 'Name', showInSearchDialog: true},
                {id: 'Program\_\_c', showInSearchDialog: true},
                {id: 'nciia\_id\_\_c', showInSearchDialog: true},
                {id: 'Legacy\_ID\_\_c', showInSearchDialog: true},
            ];
            field.options.searchTemplate = "{{Name}}, {{Program\_Start\_Date\_\_c}} - {{Program\_End\_Date\_\_c}}";
            break;
            
        case "a26":     // Team
            field.options.returnFields = [
                {id: 'Id', showInSearchDialog: false},
                {id: 'Name', showInSearchDialog: true},
            ];
            field.options.searchTemplate = "{{Name}}";
            break;
    }
    
};
if (field.mode == 'edit') { 
    // Limit the set of target objects 
    var targets = [], 
        uniqueTargets = {}; 
        
    $.each(metadata.referenceTo,function(i,r){ 
        if (($.inArray(r.objectName,targetObjects) != -1) && (!uniqueTargets[r.objectName])) { 
            targets.push(r); 
            uniqueTargets[r.objectName] = 1; 
            if (targets.length == targetObjects.length) return false; 
        } 
    }); 
    if (targets.length) { 
        
        // Make this field render as a picklist? (no - var is set to false for this implementation)
        if (renderAsPicklist) field.options.type = 'REFPICK'; 
        // Override the current referenceTo 
        metadata.referenceTo.length = 0; 
        metadata.ref = $.map(targets,function(targ){return targ.objectName;}).join();
        metadata.referenceTo = targets; 
    } 
}
// Get field renderer - [https://docs.skuid.com/latest/en/skuid/api/skuid\_ui.html#skuid.ui.getFieldRenderer](https://docs.skuid.com/latest/en/skuid/api/skuid_ui.html#skuid.ui.getFieldRenderer "Link httpsdocsskuidcomlatestenskuidapiskuid\_uihtmlskuiduigetFieldRenderer")
skuid.ui.getFieldRenderer(field)[field.mode](field, value);
// control the search layout
if ( whatPrefix === 'und') whatPrefix = "701";    // default to Campaign
updateFieldData(field, whatPrefix);
$(field.element).find("select").bind("change", function(e) {
    var val = $( "select option:selected" ).text();
    
    if( val.includes("Campaign") ) {
        
        updateFieldData(field,"701");
        
    } else if ( val.includes("Opportunity")) {
    
        updateFieldData(field,"006");
    
    } else if ( val.includes("Organization")) {
    
        updateFieldData(field,"001");
    
    } else if (val.includes("Program Cohort")) {
        
        updateFieldData(field,"a2C");
        
    } else if (val.includes("Proposal")) {
        
        updateFieldData(field,"a2m");
        
    } else if (val.includes("Team")) {
        
        updateFieldData(field,"a26");
        
    } else { 
        
        updateFieldData(field, whatPrefix);
        
    }
});