Skip to main content

Is there a way to write some kind of global script that would force a field to use a specific custom renderer for every instance of that field? I have a few fields that I need to use a custom renderer for EVERY TIME I use the field, and it would be convenient to not have to remember to change the rendering parameter of the field each time I add it in the builder.

Any ideas?

Bam!!! Thank Zach for this.

https://community.skuid.com/t/create-model-and-component-from-javascript


Ok. Very nice.

But what if I don’t want to override the field renderer for every PHONE field, I just want to override for every instance of the specific field ‘Primary_Phone__c’?


Ok, I couldn’t wait. Anyone able to check my work on this? Does this even make sense?


(function(skuid){<br><br> // Get references to our original field renderers<br> var fieldRenderers = skuid.ui.fieldRenderers;&nbsp;<br> var picklistRenderers = fieldRenderers.PICKLIST;<br> // My custom Picklist field renderer<br> var checkPicklistRenderer = function(field, value) {<br> //Object as switch statement<br> var globalPickFields = {<br> 'Case_Type__c': 'renderCaseTypes',<br> 'Primary_Phone_Type__c': 'renderPhoneTypes',<br> 'Alternate_Phone_Type': 'renderPhoneTypes',<br> 'Interaction_Intention__c': 'renderPregnancyIntentions',<br> 'Pregnancy_Intention__c': 'renderPregnancyIntentions',<br> 'Pregnancy_Intention_on_Intake__c': 'renderPregnancyIntentions',<br> 'Role__c': 'renderStaffRoles',<br> 'Primary_Staff_Role__c': 'renderStaffRoles',<br> 'Additional_Staff_Role__c': 'renderStaffRoles',<br> 'STD__c': 'renderSTDs',<br> 'Referral_Source__c': 'renderReferralSources',<br> 'Results__c': 'renderPregnancyTestResults',<br> };<br> if (globalPickFieldsdfield.id]){<br> //Use a custom renderer<br> skuid.snippet.getSnippet(globalPickFieldsdfield.id])(field,value);<br> } else {<br> //Use the standard renderer<br> picklistRenderersrfield.mode](field,value);<br> }<br> &nbsp;<br> };<br>&nbsp; &nbsp;// Override all of Skuid's standard Picklist field renderers to call our custom renderer<br>&nbsp; &nbsp;picklistRenderers.read = picklistRenderers.readonly = picklistRenderers.edit = function(){<br>&nbsp; &nbsp; &nbsp; &nbsp;checkPicklistRenderer.apply(this,arguments);<br>&nbsp; &nbsp;};<br><br>})(skuid);

I feel like I’m in danger of a loop here. Is there any way to still use the standard renderer if the check fails? As it’s currently written, if field.id isn’t a key in the globalPickFields object, I’m going to keep checking infinitely, right?


Hey, friends. This isn’t answered!

Can anyone help me avoid the infinite loop?


And I’ve confirmed that it is an infinite loop.


Matt,

I think the bit that you are missing from Zach’s response is the originalPhone part. Your script is completely replacing the renderers that Skuid uses, including the standard renderers that you still want to use if the field isn’t one of your globalPickFields. Try something like this:


(function(skuid){ &#47;&#47; Get references to our original field renderers var picklistRenderers = skuid&#46;ui&#46;fieldRenderers&#46;PICKLIST, originalPicklistRenderers = skuid&#46;$&#46;extend({},picklistRenderers), &#47;&#47; Object as switch statement globalPickFields = { 'Case_Type__c': 'renderCaseTypes', 'Primary_Phone_Type__c': 'renderPhoneTypes', 'Alternate_Phone_Type': 'renderPhoneTypes', 'Interaction_Intention__c': 'renderPregnancyIntentions', 'Pregnancy_Intention__c': 'renderPregnancyIntentions', 'Pregnancy_Intention_on_Intake__c': 'renderPregnancyIntentions', 'Role__c': 'renderStaffRoles', 'Primary_Staff_Role__c': 'renderStaffRoles', 'Additional_Staff_Role__c': 'renderStaffRoles', 'STD__c': 'renderSTDs', 'Referral_Source__c': 'renderReferralSources', 'Results__c': 'renderPregnancyTestResults' }; &#47;&#47; Override all of Skuid's standard Picklist field renderers to call our custom renderer picklistRenderers&#46;read = picklistRenderers&#46;readonly = picklistRenderers&#46;edit = function(field,value){ if (globalPickFieldsefield&#46;id]){ &#47;&#47;Use a custom renderer skuid&#46;snippet&#46;getSnippet(globalPickFieldsefield&#46;id])(field,value); } else { &#47;&#47;Use the standard renderer originalPicklistRenderersrfield&#46;mode](field,value); } }; })(skuid);

Thanks, J.

What’s up with the 


var orginalPicklistRenderers =&nbsp;$.extend({},picklistRenderers);

?

How is that different than just


var orginalPicklistRenderers = picklistRenderers;

 ?

Thanks!


jQuery.extend is a jQuery method that merges the contents of objects and returns the combined object. In this case, it’s an easy way to do a shallow copy of an object. The way you were doing it was just creating a new reference to the same object, not creating a distinct copy. You could also have written the originalPicklistRenderers part as…


var originalPicklistRenderers = { read : picklistRenderers.read, readonly : picklistRenderers.readonly, edit : picklistRenderers.edit, };

That would be more explicit than using extend (which can sometimes overwrite more than you want).


Makes sense! Thanks. 🙂


So, I’m still getting an infinite loop with the following code:


<br>// Get references to our original picklist field renderers var picklistRenderers = skuid.ui.fieldRenderers.PICKLIST;&nbsp;<br> var originalPicklistRenderers = {<br> read : picklistRenderers.read,<br> readonly : picklistRenderers.readonly,<br> edit : picklistRenderers.edit<br> };<br> //Object as switch statement - stores field API names and corresponding snippet names<br> var globalPickFields = {<br> 'Case_Type__c': 'renderCaseTypes',<br> 'Primary_Phone_Type__c': 'renderPhoneTypes',<br> 'Alternate_Phone_Type__c': 'renderPhoneTypes',<br> 'Interaction_Intention__c': 'renderPregnancyIntentions',<br> 'Pregnancy_Intention__c': 'renderPregnancyIntentions',<br> 'Pregnancy_Intention_on_Intake__c': 'renderPregnancyIntentions',<br> 'Father_of_the_Baby_Intention__c': 'renderPregnancyIntentions',<br> 'Role__c': 'renderStaffRoles',<br> 'Primary_Staff_Role__c': 'renderStaffRoles',<br> 'Additional_Staff_Role__c': 'renderStaffRoles',<br> 'STD__c': 'renderSTDs',<br> 'Sexual_Exposure_to_What_STD__c' : 'renderSTDs',<br> 'STD_Picklist': 'renderSTDs',<br> 'Referral_Source__c': 'renderReferralSources',<br> 'Results__c': 'renderPregnancyTestResults',<br> };<br> // Check all picklists to see if they should be overridden<br> var checkPicklistRenderer = function(field, value) {<br> // If the field is one of the global picklist fields, run the snippet for it<br> if (globalPickFieldsdfield.id]){<br> //Use a custom renderer<br> skuid.snippet.getSnippet(globalPickFieldsdfield.id])(field,value);<br> } else {<br> //Use the standard renderer<br> originalPicklistRenderersrfield.mode](field,value);<br> &nbsp; }<br> };<br>&nbsp; &nbsp;// Override all of Skuid's standard Picklist field renderers to call our custom renderer<br>&nbsp; picklistRenderers.read = picklistRenderers.readonly = picklistRenderers.edit = function(){<br>&nbsp; &nbsp; &nbsp; &nbsp;checkPicklistRenderer.apply(this,arguments);<br>&nbsp; &nbsp;};


When I call originalPicklistRenderersfield.mode; (from this section of code or from one of the custom snippets) it’s looping back to checkPicklistRenderer.apply(this,arguments);

Using the $.extend() syntax didn’t help. 

Help?


Did you try overwriting the the renderers the way I did at the bottom of my script?


picklistRenderers.read = picklistRenderers.readonly = picklistRenderers.edit = function(field,value){ if (globalPickFields[field.id]){ //Use a custom renderer skuid.snippet.getSnippet(globalPickFields[field.id])(field,value); } else { //Use the standard renderer originalPicklistRenderers[field.mode](field,value); } };

Ah, I missed that change. Thanks, J.


Hmm. Still getting the loop.


Did you try it using the extend approach too? The issue could be in one of the snippets your globalPickFields references too.


I tried the extend approach, with the same result.

All of my custom renderers use the line


originalPicklistRenderers[field.mode](field,value);

to render, and this loops back to 


picklistRenderers.read = picklistRenderers.readonly = picklistRenderers.edit = function(field,value){ 



From the call stack, it looks like m.PICKLIST.readonly (the standard renderer) is calling f.readonly (my override). When my override tries to call my reference to the standard renderer, the loop starts again.

Somehow, my reference to the original renderer is still being overridden??


Finally! I took a hint from Zach’s original post. This seems to be working:


//////////////////////////////////////////////<br>// Global Renderer Override //<br>//////////////////////////////////////////////<br>// Get references to our original picklist field renderers<br>var picklistRenderers = skuid.ui.fieldRenderers.PICKLIST;&nbsp;<br>var oPickRead = picklistRenderers.read,<br>oPickReadonly = picklistRenderers.readonly,<br>oPickEdit = picklistRenderers.edit;<br>//Object as switch statement - stores field API names and corresponding snippet names<br>var globalPickFields = {<br>'Case_Type__c': 'renderCaseTypes',<br>'Primary_Phone_Type__c': 'renderPhoneTypes',<br>'Alternate_Phone_Type__c': 'renderPhoneTypes',<br>'Interaction_Intention__c': 'renderPregnancyIntentions',<br>'Pregnancy_Intention__c': 'renderPregnancyIntentions',<br>'Pregnancy_Intention_on_Intake__c': 'renderPregnancyIntentions',<br>'Father_of_the_Baby_Intention__c': 'renderPregnancyIntentions',<br>'Role__c': 'renderStaffRoles',<br>'Primary_Staff_Role__c': 'renderStaffRoles',<br>'Additional_Staff_Role__c': 'renderStaffRoles',<br>'STD__c': 'renderSTDs',<br>'Sexual_Exposure_to_What_STD__c' : 'renderSTDs',<br>'STD_Picklist': 'renderSTDs',<br>'Referral_Source__c': 'renderReferralSources',<br>'Results__c': 'renderPregnancyTestResults',<br>'UPT_Results__c': 'renderPregnancyTestResults'<br>};<br>// Override all of Skuid's standard Picklist field renderers to call our custom renderer<br>picklistRenderers.read = picklistRenderers.readonly = picklistRenderers.edit = function(field,value){<br>&nbsp; &nbsp; &nbsp; &nbsp;// If the field is one of the global picklist fields, run the snippet for it<br>if (globalPickFieldsdfield.id]){<br>//Use a custom renderer<br>skuid.snippet.getSnippet(globalPickFieldsdfield.id])(field,value);<br>} else {<br>//Use the standard renderer<br>if (field.mode === 'read') {<br>oPickRead.apply(this,arguments);<br>} else if (field.mode === 'readonly'){<br>oPickReadonly.apply(this,arguments);<br>} else {<br>oPickEdit.apply(this,arguments);<br>}<br>// originalPicklistRenderersrfield.mode](field,value);<br> &nbsp; }<br>&nbsp; &nbsp;};

Matt,

If your custom renderers (e.g. renderCaseTypesrenderPhoneTypes, etc.) themselves point to the standard renderers, I’m pretty sure that’s where your infinite loop is getting introduced:

  1. Override standard renderer with custom renderer

  2. Custom renderer calls standard renderer

  3. Standard renderer has been overridden to point to the custom renderer

  4. Customer renderer calls standard renderer


You’ll need to pass in the reference to the original versions of those renderers, or use a different renderer (skuid.ui.fieldRenderers.TEXT.readonly might work here).


Thanks for all the help, J. You’re awesome.

I realized that I only really need to override the renderer in edit scenarios, so I ended up with this:


&#47;&#47; Get references to our original picklist field renderers var picklistRenderers = skuid&#46;ui&#46;fieldRenderers&#46;PICKLIST;&nbsp;<br /> var oPickEdit = picklistRenderers&#46;edit;<br /> &#47;&#47;Object as switch statement - stores field API names and corresponding snippet names<br /> var globalPickFields = {<br /> 'Case_Type__c': 'renderCaseTypes',<br /> 'Primary_Phone_Type__c': 'renderPhoneTypes',<br /> &#46;&#46;&#46;Lots more options here&#46;&#46;&#46;<br /> 'Referral_Source__c': 'renderReferralSources',<br /> 'UPT_Results__c': 'renderPregnancyTestResults'<br /> };<br /> &#47;&#47; Override Skuid's standard edit Picklist field renderers to call our custom renderer<br /> picklistRenderers&#46;edit = function(field,value){<br />&nbsp; &nbsp; &nbsp; &nbsp;&#47;&#47; If the field is one of the global picklist fields, run the snippet for it<br /> if (globalPickFieldsdfield&#46;id]){<br /> &#47;&#47;Use a custom renderer<br /> skuid&#46;snippet&#46;getSnippet(globalPickFieldsdfield&#46;id])(field,value);<br /> } else {<br /> &#47;&#47;Use the standard renderer<br /> oPickEdit&#46;apply(this,arguments);<br /> &nbsp; }<br />&nbsp; &nbsp;};


And it works!
All of the custom renderer snippets are in the same inline javascript, so they have access to the standard renderer through the oPickEdit variable. As an example, I’m accessing it like so:


'renderReferralSources': function (field, value) {<br />&nbsp; if (!picklistRows) getPicklistRows();<br /> var filteredList = picklistRows&#46;filter(function(row){<br /> return row&#46;Picklist__c === 'Referral Sources';<br /> });<br /> &nbsp; &nbsp;var picklistEntries = s];<br /> &nbsp; &nbsp;<br /> &nbsp; &nbsp;$&#46;each(filteredList,function(i,row){<br /> &nbsp; &nbsp; if (row&#46;Default__c) {<br /> &nbsp; &nbsp; picklistEntries&#46;unshift(<br /> &nbsp; &nbsp; { value: row&#46;Picklist_Value__c, label: row&#46;Picklist_Value__c, defaultValue: true, active: true }<br /> &nbsp; &nbsp; );<br /> &nbsp; &nbsp; } else {<br /> &nbsp; &nbsp; picklistEntries&#46;push(<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ value: row&#46;Picklist_Value__c, label: row&#46;Picklist_Value__c, defaultValue: false, active: true }<br /> &nbsp; &nbsp; );<br /> &nbsp; &nbsp; }<br /> &nbsp; &nbsp;});<br /> &nbsp; &nbsp;field&#46;metadata&#46;picklistEntries = picklistEntries;<br /> &nbsp; &nbsp;if (field&#46;mode === 'edit') {<br /> oPickEdit&#46;apply(this,arguments);<br /> } else &nbsp;{<br /> picklistRenderersrfield&#46;mode](field,value);<br /> }<br />}


We have an object which stores custom pickstlist values for certain picklists, each value on its own row. This allows a high degree of picklist customization by users with the appropriate permissions through a skuid interface. Basically, we’re using skuid to replicate the “Picklists” metadata that’s in beta for SFDC right now, except we’re allowing ‘administrator’ type users to customize the ‘metadata’ for the picklist values through the skuid ui without touching the salesforce setup back end.


Thanks again for your help!