Upgraded to summer GA and this line now prevents a skuid page from being shown.

  • 1
  • Question
  • Updated 4 years ago
  • Answered
This is probably something stupid, but I wanted to ask before I spend hours trying to figure it out.

I upgraded to the latest skuid version this morning, and one of our pages no longer loads. Once I dug into it, I found that it was a single line in a JS snippet causing the problem:


field.model.updateRow(field.row, field.id, '');

If I comment that out, it displays and functions normally, but this line worked before the update.

Any thoughts as to why this is?
Photo of Korey

Korey

  • 1,098 Points 1k badge 2x thumb
  • sadness

Posted 4 years ago

  • 1
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Try changing the line to this:

field.model.updateRow(field.row, field.id, '', { initiatorId: field._GUID });

and see if that fixes it.
Photo of Korey

Korey

  • 1,098 Points 1k badge 2x thumb
Worked like a charm, thanks Zach!
Photo of Korey

Korey

  • 1,098 Points 1k badge 2x thumb
I spoke too soon, the page renders, however the field that renders as a custom picklist no longer updates. Here is the code in it's entirety.


var field = arguments[0];
var value = arguments[1];
$ = skuid.$;

//  Build the Options for the PICKLIST
var customOpts = [
    { label: '--None--', value: "" },
    { label: 'Initial product install' },
    { label: 'Importing my gold image' },
    { label: 'Creating unattend file and initial desktop deployment' },
    { label: 'Layering a new application' },
    { label: 'Updating an OS or application layer' },
    { label: 'Right sizing my deployment' },
    { label: 'Desktop problem (booting, runtime behavior or performance)' },
    { label: 'A feature in the management console is not working as expected' },
    { label: 'Just a question' },
    { label: 'Unidesk web site problem' },
    { label: 'Documentation problem' },
    { label: 'Other' }
];


// set the default value in the model
//field.model.updateRow(field.row, field.id, '');
field.model.updateRow(field.row, field.id, '', { initiatorId: field._GUID });

//  Render the options as a PICKLIST
var customSelect = skuid.ui.renderers.PICKLIST.edit({
    entries : customOpts,
    required : true,
    value : value
}).change(function() {
    //  Update the row in the target object
    if ($(this).val() == 'Other') {
        $('#textProblemOther').show();
        field.model.updateRow(field.row,field.id,$('#textProblemOther').val());
    }
    else {
        $('#textProblemOther').hide();
        field.model.updateRow(field.row,field.id,skuid.$(this).val());
    }
});

//  Append the PICKLIST to the DOM element
field.element.append(customSelect);

// Now create the text field to support the 'Other' use case
var textContent = skuid.ui.renderers.TEXT.edit(field, value).change(function() {
    field.model.updateRow(field.row,field.id,skuid.$(this).val());
});
// set the id and make it invisible to start
textContent[0].id = 'textProblemOther';
textContent[0].style.display = 'none';
// and add to the DOM
field.element.append(textContent);
Photo of Korey

Korey

  • 1,098 Points 1k badge 2x thumb
To clarify: the field renders as a picklist, but any time I select anything it doesn't fire the updates.
Photo of Korey

Korey

  • 1,098 Points 1k badge 2x thumb
This problem is becoming a very big deal, as customers cannot open support cases through the portal because of this change. I hate to be that guy, but can anyone at least take a guess for me?
Photo of Moshe Karmel

Moshe Karmel, Champion

  • 8,646 Points 5k badge 2x thumb
Part of the issue here is that you're doing field updates inside of a field renderer which I believe is not recommended. One way that I often get around this, is setting values in a page load snippet. I would try setting your default value on the page load by adding an "inline" snippet which updates the row to a blank string.

(function(skuid){   var $ = skuid.$;
   $(function(){
       var model = skuid.$M('YourModelName');
       var row = model.getFirstRow();
       model.updateRow(row,'Your_Field__c','');
   });
})(skuid);
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Try this:

var field = arguments[0];
var value = arguments[1];
var $ = skuid.$;

//  Build the Options for the PICKLIST
var customOpts = [
    { label: '--None--', value: "" },
    { label: 'Initial product install' },
    { label: 'Importing my gold image' },
    { label: 'Creating unattend file and initial desktop deployment' },
    { label: 'Layering a new application' },
    { label: 'Updating an OS or application layer' },
    { label: 'Right sizing my deployment' },
    { label: 'Desktop problem (booting, runtime behavior or performance)' },
    { label: 'A feature in the management console is not working as expected' },
    { label: 'Just a question' },
    { label: 'Unidesk web site problem' },
    { label: 'Documentation problem' },
    { label: 'Other' }
];


// set the default value in the model
//field.model.updateRow(field.row, field.id, '');
if (!value && (value!=='')) {
   field.model.updateRow(field.row, field.id, '', { initiatorId: field._GUID });
}

// Now create the text field to support the 'Other' use case
var textContent = skuid.ui.renderers.TEXT.edit(field, value).change(function() {
    field.model.updateRow(field.row,field.id,$(this).val(), { initiatorId: field._GUID });
});

//  Render the options as a PICKLIST
var customSelect = skuid.ui.renderers.PICKLIST.edit({
    entries : customOpts,
    required : true,
    value : value
}).change(function() {
    //  Update the row in the target object
    if ($(this).val() == 'Other') {
        textContent.show();
        field.model.updateRow(field.row,field.id,textContent.val(), { initiatorId: field._GUID });
    }
    else {
        textContent.hide();
        field.model.updateRow(field.row,field.id,$(this).val(), { initiatorId: field._GUID });
    }
});

//  Append the PICKLIST to the DOM element
field.element.append(customSelect);


// set the id and make it invisible to start
textContent[0].id = 'textProblemOther';
textContent[0].style.display = 'none';
// and add to the DOM
field.element.append(textContent);
Photo of Korey

Korey

  • 1,098 Points 1k badge 2x thumb
Zach, this fixed it for me. I had to do a little shuffling around of inline snippets that were causing rendering issues but you are a godsend. I definitely owe you a beer / whiskey / coffee, thank you so much!
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
No problem Korey.

FYI for other users facing this issue, the main problem here was, as Moshe pointed out, the following line, which performed an unconditional initialization of the field:

field.model.updateRow(field.row, field.id, '');

The problem with this line is that it would be run every time the field renderer is run. So no matter what Model data changes you made using your picklists / text, your field renderer would eliminate them the next time it was run.

This is easy to avoid: just wrap this in a block that checks the current value and selectively runs the line based on whether there is a value or not:

if (!value && (value!=='')) {
   field.model.updateRow(field.row, field.id, '', { initiatorId: field._GUID });
}

The reason that your field renderer was working pre-Summer 14 was that the field renderer was only ever getting run once, so this wasn't a problem.

But in Summer 14, and going forward, we've made some changes under the hood to keep Models / Components more automatically in sync. So when your Field Renderer initiates a Model data change, e.g. via field.model.updateRow(field.row, field.id, "someValue"), this change is sent to the Model, and then, in Summer 14, skuid goes and notifies all "registered" parts of the UI, telling them about the change --- meaning that all registered skuid.ui.Field objects will be re-rendered, meaning that any Custom Field Renderers on them will be run.

This is all very ideal when using standard Skuid, but with Custom Field Renderers, it can be problematic if your code is not written correctly.

The challenge is that we DON'T want Skuid to rerender the Field that initiated the change! Your Field renderer already knows about what happened --- it doesn't need to be told again!

How to solve this?

Enter the concept of the "initiator". 

Wherever you call updateRow within your Custom Field Renderer, you need to pass in an "initiatorId" parameter where you are saying, "There is a specific Field that initiated this change --- Me. So don't re-render me." The "Me" part of the equation is provided by field._GUID, the unique Id of the skuid.ui.Field

field.model.updateRow(field.row, field.id, "foo bar", { initiatorId: field._GUID });