Skip to main content

I have created a custom component very similar to the one described is the excellent tutorial Highlighting Critical Data using Templates and Custom Components.

Here’s my inline JavaScript code:


skuid.componentType.register('totalMargin', function (element) {<b>
</b> //Registers Component
var $ = skuid.$;
var m = skuid.model.getModel('Quote');
var row = m.getFirstRow();<b>
</b> var totalFOB = row.Total_FOB_Weighted_Average__c;
var totalExpert = row.Total_Expert_Price_Weighted_Average__c;
var totalTypical = row.Total_Typical_Price_Weighted_Average__c;
var totalFloor = row.Total_Floor_Price_Weighted_Average__c;
var cssClass = null;<b>
</b> if (totalFOB >= totalExpert) {
cssClass = 'box-green';
} else if (totalFOB >= totalTypical) {
cssClass = 'box-yellow';
} else if (totalFOB >= totalFloor) {
cssClass = 'box-orange';
} else {
cssClass = 'box-red';
}<b>
</b> // This wraps the calculated value in the HTML code that applies the same
// styles as we used with the template
var text =
"<div class='box " +
cssClass +
" ui-widget'>" +
"<div class='nx-pagetitle-subtitle' style='text-transform: uppercase;'>" +
" Total Margin " +
"</div>" +
"<div class = 'nx-pagetitle-maintitle'>" +
"{{Total_Margin__c}}" +
"</div>" +
"</div>";<b>
</b> element.append(
m.mergeRow(row, text)
); // Sticks all this HTML code into our custom component.
});


Notice that the background color of the template to colored-coded and conditionally set in the JavaScript.

My issue is that the CSS seems to be correctly set but not applied until I perform a page refresh F5.

Here’s the workflow:


  1. User performs a mass action and updates one or more rows

  2. The mass action is defined as Multiple Actions and one of the actions is Update Models

  3. The last step is Unblock the UI

The models are updated correctly. However, the new CSS is not applied until I hit F5.


What am I missing?


Hi, Irvin,
This code is only running on page load. You need a way to listen for changes in your model to update the CSS. Try something like this:


var editor = new skuid.ui.Editor(); editor.registerModel(m); 

And then extend the editor’s standard functions like handleSave() and handleChange() so that on save or on change, the CSS is updated. If you only want to update the CSS when the model is saved, this will be pretty simple. Just include


editor.handleSave = function(totalSuccess) { skuid.ui.Editor.prototype.handleSave.call(editor, totalSuccess) //Update the css based on model values }

See the skuid.ui.Editor documentation for more info. Does this help? 


Thanks for the quick reply. Yes, makes sense.  Let me give it a try today and report back.


Hi,


Still unable to get this to work. Here’s my use case:


  1. Data model is Quote and Quote Line Item

  2. On Page Load, render custom component that displays a Quote KPI w/ custom CSS (this works)

  3. Edit a Line Item and Save changes

  4. Custom component should updated, both the value and CSS (neither are being refreshed)

Here’s my custom component JS:



skuid.componentType.register('totalOpportunityLeft', function(element) {
// Registers Component
var $ = skuid.$;
var m = skuid.model.getModel('Quote');
var row = m.getFirstRow();
// Listen for changes on the Quote model
var editor = new skuid.ui.Editor(element);
editor.registerModel(m);
// handleSave callback
editor.handleSave = function(totalSuccess) {

console.log('editor.handleSave');

skuid.ui.Editor.prototype.handleSave.call(editor, totalSuccess);
// Update the css based on model values
setScoreCSS();
};

// handleSave callback
editor.handleChange = function() {
console.log('editor.handleChange');
skuid.ui.Editor.prototype.handleChange.call(editor);
// Update the css based on model values
setScoreCSS();
};
// This wraps the calculated value in the HTML code that applies the same
// styles as we used with the template
var text =
"<div class='box " +
getScoreCSS() +
" ui-widget'>" +
"<div class='nx-pagetitle-subtitle' style='text-transform:uppercase;'>" +
" Total Opportunity Left " +
"</div>" +
"<div class='nx-pagetitle-maintitle'>" +
"{{Total_Opportunity_Left__c}}" +
"</div>" +
"</div>";
// Sticks all this HTML code into our custom component.
element.append(
m.mergeRow(row, text)
);
// Determine score based CSS class
function getScoreCSS() {
var totalFOB = row.Total_FOB_Weighted_Average__c;
var totalExpert = row.Total_Expert_Price_Weighted_Average__c;
var totalTypical = row.Total_Typical_Price_Weighted_Average__c;
var totalFloor = row.Total_Floor_Price_Weighted_Average__c;

console.log('getScoreCSS: totalFOB ' + totalFOB);
console.log('getScoreCSS: totalExpert ' + totalExpert);
console.log('getScoreCSS: totalTypical ' + totalTypical);
console.log('getScoreCSS: totalFloor ' + totalFloor);
var cssClass = null;
if (totalExpert === 0 &amp;&amp; totalTypical === 0 &amp;&amp; totalFloor === 0) {
cssClass = 'box-simple';
}
if (totalFOB >= totalExpert) {
cssClass = 'box-green';
} else if (totalFOB >= totalTypical) {
cssClass = 'box-yellow';
} else if (totalFOB >= totalFloor) {
cssClass = 'box-orange';
} else {
cssClass = 'box-red';
}
console.log('getScoreCSS: ' + cssClass);
return cssClass;
}
function setScoreCSS() {

console.log('setScoreCSS');

$('#totalOpportunityLeft')
.removeClass('box-simple box-red box-orange box-yellow box-green')
.addClass(getScoreCSS());
}
});


Note that the model callbacks are never being called back.


Hi Emily,

Tried a different approach and I think I got it.

Stumbled across this post:  Update page load snippet

So, I reverted my KPIs back to using templates and using this snippet with the appropriate model action:


(function(skuid) {&nbsp; &nbsp; <br>var $ = skuid.$;<br>&nbsp; &nbsp; // Register a snippet to run&nbsp;<br>&nbsp; &nbsp; skuid.snippet.registerSnippet('setCSS', function(changeInfo) {<br>&nbsp; &nbsp; &nbsp; &nbsp; console.log('setCSS');<br>&nbsp; &nbsp; &nbsp; &nbsp; var quoteModel = skuid.model.getModel('Quote');<br>&nbsp; &nbsp; &nbsp; &nbsp; var row = quoteModel.getFirstRow();<br>&nbsp; &nbsp; &nbsp; &nbsp; var totalFOB = row.Total_FOB_Weighted_Average__c;<br>&nbsp; &nbsp; &nbsp; &nbsp; var totalExpert = row.Total_Expert_Price_Weighted_Average__c;<br>&nbsp; &nbsp; &nbsp; &nbsp; var totalTypical = row.Total_Typical_Price_Weighted_Average__c;<br>&nbsp; &nbsp; &nbsp; &nbsp; var totalFloor = row.Total_Floor_Price_Weighted_Average__c;<br>&nbsp; &nbsp; &nbsp; &nbsp; console.log('totalFOB ' + totalFOB);<br>&nbsp; &nbsp; &nbsp; &nbsp; console.log('totalExpert ' + totalExpert);<br>&nbsp; &nbsp; &nbsp; &nbsp; console.log('totalTypical ' + totalTypical);<br>&nbsp; &nbsp; &nbsp; &nbsp; console.log('totalFloor ' + totalFloor);<br>&nbsp; &nbsp; &nbsp; &nbsp; var cssClass = null;<br>&nbsp; &nbsp; &nbsp; &nbsp; if (totalExpert === 0 &amp;&amp; totalTypical === 0 &amp;&amp; totalFloor === 0) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cssClass = 'box-simple';<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; if (totalFOB &gt;= totalExpert) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cssClass = 'box-green';<br>&nbsp; &nbsp; &nbsp; &nbsp; } else if (totalFOB &gt;= totalTypical) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cssClass = 'box-yellow';<br>&nbsp; &nbsp; &nbsp; &nbsp; } else if (totalFOB &gt;= totalFloor) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cssClass = 'box-orange';<br>&nbsp; &nbsp; &nbsp; &nbsp; } else {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cssClass = 'box-red';<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; $('#totalFOB')<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .removeClass('box-simple box-red box-orange box-yellow box-green')<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .addClass(cssClass);<br>&nbsp; &nbsp; &nbsp; &nbsp; $('#totalMargin')<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .removeClass('box-simple box-red box-orange box-yellow box-green')<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .addClass(cssClass);<br>&nbsp; &nbsp; &nbsp; &nbsp; $('#totalOpportunityLeft')<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .removeClass('box-simple box-red box-orange box-yellow box-green')<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .addClass(cssClass);<br>&nbsp; &nbsp; });<br>&nbsp; &nbsp; // Run the snippet initially on page load<br>&nbsp; &nbsp; $('.nx-page').one('pageload', function() {<br>&nbsp; &nbsp; &nbsp; &nbsp; skuid.snippet.getSnippet('setCSS')();<br>&nbsp; &nbsp; });<br>})(skuid);





Nice!! That sounds a little easier than what I was recommending 🙂


Not only does Skuid have a great declarative capability but the true power is in the API.  As I dig deeper and deeper, I am just amazed as to what I can do with “snippets” of code to amplify my application, no pun intended. 🙂


Irvin - would you mind copying that last quote and putting it up as an App Exchange Review?  (Yes that was a shameless request).  The link is here:  https://appexchange.salesforce.com/listingDetail?listingId=a0N30000009wyDjEAI

What you are saying is not often understood about our platform.   


Thanks for doing this Irvin.