Custom Component CSS not refreshing

  • 1
  • Question
  • Updated 4 years ago
  • Answered
  • (Edited)
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) {
    //Registers Component
    var $ = skuid.$;
    var m = skuid.model.getModel('Quote');
    var row = m.getFirstRow();
    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;
    if (totalFOB >= totalExpert) {
        cssClass = 'box-green';
    } else if (totalFOB >= totalTypical) {
        cssClass = 'box-yellow';
    } else if (totalFOB >= totalFloor) {
        cssClass = 'box-orange';
    } else {
        cssClass = 'box-red';
    }
    // 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>";
    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?

Photo of Irvin Waldman

Irvin Waldman, Champion

  • 9,006 Points 5k badge 2x thumb

Posted 4 years ago

  • 1
Photo of Emily Davis

Emily Davis, Employee

  • 3,502 Points 3k badge 2x thumb
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? 
Photo of Emily Davis

Emily Davis, Employee

  • 3,502 Points 3k badge 2x thumb
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? 
Photo of Irvin Waldman

Irvin Waldman, Champion

  • 9,006 Points 5k badge 2x thumb
Thanks for the quick reply. Yes, makes sense.  Let me give it a try today and report back.
Photo of Irvin Waldman

Irvin Waldman, Champion

  • 9,006 Points 5k badge 2x thumb
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 && totalTypical === 0 && 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.
Photo of Irvin Waldman

Irvin Waldman, Champion

  • 9,006 Points 5k badge 2x thumb
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) {    
var $ = skuid.$;
    // Register a snippet to run 
    skuid.snippet.registerSnippet('setCSS', function(changeInfo) {
        console.log('setCSS');
        var quoteModel = skuid.model.getModel('Quote');
        var row = quoteModel.getFirstRow();
        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('totalFOB ' + totalFOB);
        console.log('totalExpert ' + totalExpert);
        console.log('totalTypical ' + totalTypical);
        console.log('totalFloor ' + totalFloor);
        var cssClass = null;
        if (totalExpert === 0 && totalTypical === 0 && 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';
        }
        $('#totalFOB')
            .removeClass('box-simple box-red box-orange box-yellow box-green')
            .addClass(cssClass);
        $('#totalMargin')
            .removeClass('box-simple box-red box-orange box-yellow box-green')
            .addClass(cssClass);
        $('#totalOpportunityLeft')
            .removeClass('box-simple box-red box-orange box-yellow box-green')
            .addClass(cssClass);
    });
    // Run the snippet initially on page load
    $('.nx-page').one('pageload', function() {
        skuid.snippet.getSnippet('setCSS')();
    });
})(skuid);
Photo of Emily Davis

Emily Davis, Employee

  • 3,502 Points 3k badge 2x thumb
Nice!! That sounds a little easier than what I was recommending :)
Photo of Irvin Waldman

Irvin Waldman, Champion

  • 9,006 Points 5k badge 2x thumb
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. :)
Photo of Rob Hatch

Rob Hatch, Official Rep

  • 44,006 Points 20k badge 2x thumb
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.   
Photo of Rob Hatch

Rob Hatch, Official Rep

  • 44,006 Points 20k badge 2x thumb
Thanks for doing this Irvin.