Javascript throwing unsaved changes error when no changes have been made.

I’m getting an uncaught model (unsaved changes) when I run the following script more than once. I tried to implement a model check and save if there were changes, but to no avail. I still get hte uncaught changes error on the ‘Open’ model.

What am I missing?

Here’s the code:

var mO = skuid.$M('Open'),&nbsp; &nbsp; model = skuid.$M('ApptInteractions'),<br>&nbsp; &nbsp; condition = model.getConditionByName('Date'),<br>&nbsp; &nbsp; curDate = condition.value;<br>var jsDate = (curDate == 'TODAY') ? new Date() : skuid.time.parseSFDate(curDate);<br>jsDate.setDate(jsDate.getDate()-1);<br>var prevDate = skuid.time.getSFDate(jsDate);<br>//Set Conditions<br>model.setCondition(condition, prevDate);<br>mO.setCondition(mO.getConditionByName('OpenDate'), prevDate);<br>//Requery models (if unsaved, save first)<br>if (!model.hasChanged) {<br>&nbsp; &nbsp; model.updateData();<br>} else {<br>&nbsp; &nbsp; model.save({<br>&nbsp; &nbsp; callback: function(results){<br>&nbsp; &nbsp; &nbsp; &nbsp; if(results.totalsuccess) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; model.updateData();<br>&nbsp; &nbsp; &nbsp; &nbsp; } else {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log('Appointments model save failed.');<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; }});<br>}<br>if (!mO.hasChanged) {<br>&nbsp; &nbsp; mO.updateData();<br>} else {<br>&nbsp; &nbsp; mO.save({<br>&nbsp; &nbsp; callback: function(results){<br>&nbsp; &nbsp; &nbsp; &nbsp; if(results.totalsuccess) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mO.updateData();<br>&nbsp; &nbsp; &nbsp; &nbsp; } else {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log('Appointments model save failed.');<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; }});<br>}<br><br>//Refresh template<br>skuid.component.getById('DateTemplate').render(); 

Thanks!

It looks like every time I activate and set the value of a condition on a model, and then try to query that model, it’s throwing an “uncaught model ‘Model’ has unsaved changes.” error.

Under what circumstances does this script get run?

I’m in the mobile page builder. User clicks a button (to display open appointments for the previous day). 

I get the same error when the user clicks a different button and activates this action framework set:

  1. Activate and set value of model condition.
  2. Query Model
  3. Set Main Panel
It throws the error before the query, even though I’ve made no changes to the model (as far as I can tell).

What happens if you run a “Cancel Models” action / run model.cancel() and m0.cancel() in JavaScript before everything else?

No dice.

Fascinatingly, the error is getting triggered from the updateData() within the callback of the save() function:

How could there be unsaved changes in the model? It was just saved!

Better check to see what changes there are — there must be something. Before the m0.updateData in the callback, do:

console.log('Does m0 still have changes: ’ + m0.hasChanged);
console.log(m0.changes);

slick. I didn’t know model.changes was a thing.

What am I looking at?

Looks like something is populating a value for the Name field on all of the rows in your Model, immediately after save — do you have any After-Save Actions set up on a Deck in your page? Or any other JavaScript that might be bound to the save event on this Model?

Zach,

I searched through the XML, and couldn’t find anything. I don’t have any after-save actions on the panel in question.

Mobile doesn’t have any model actions, so that’s out (also checked the XML just in case).

The only thing I can think that might impact Name is a field renderer we have on Name on other panels… but the field isn’t even rendered on the page, so I don’t think that should make any difference?


Aha! I bet that’s it. Is there an updateRow() somewhere in the Field Renderer javascript?

Matt, checked your renderer.fullName snippet, found this bit:

value = CC_SCH.getFullNameFromField(field);<br>skuid.ui.fieldRenderers[field.metadata.displaytype].read( field, value );<br>// If our value is not equal to the current value of the "Name" field,<br>// do an updateRow<br>if (field.Name !== value) {<br> model.updateRow(row,'Name',value,{ initiatorId: field._GUID });<br>}


I’m posting this to the Community for posterity to help others who run into a similar conundrum. One problem with the original was that field.Name was meaningless (i think you meant field.row.Name), but the bigger problem is that you are running the update check after the field renderer. Here’s how I would do this:

var <b>combinedValue</b> = CC_SCH.getFullNameFromField(field);<br><b>// If our combined value is not equal to the current value of the field,</b><br><b>// do an update, and change value appropriately</b><br>if (<b>combinedValue</b> !== value) {<br><b>&nbsp; &nbsp;value = combinedValue;<br></b>&nbsp; &nbsp;model.updateRow(row,'Name',value,{ initiatorId: field._GUID });<br>}<br>skuid.ui.fieldRenderers[field.metadata.displaytype].read( field, value );



Yep…

/*** Name Renderer: &nbsp;registers Name Fields with the Model<br>* and concatenates the names as they are being changed.<br>**/<br>var field = arguments[0],<br>value = skuid.utils.decodeHTML(arguments[1]),<br>model = field.model,<br>row = field.row;<br>//field.metadata.displaytype<br>//register related fields.<br>field.model.registerField(field, "First_Name__c");<br>field.model.registerField(field, "Middle_Name__c");<br>field.model.registerField(field, "Last_Name__c");<br>value = CC_SCH.getFullNameFromField(field);<br>skuid.ui.fieldRenderers[field.metadata.displaytype].read( field, value );<br>// If our value is not equal to the current value of the "Name" field,<br>// do an updateRow<br>if (field.Name !== value) {<br>model.updateRow(row,'Name',value,{ initiatorId: field._GUID });<br>}

Nice… thanks, Zach!


Zach… I’m still getting the error after updating the renderer as you indicated.

It’s still changing the value of Name after every save, apparently.

What’s the best way around this?

Matt, ideally what I would do is to remove the Field Renderer altogether — and use Model Actions. I would setup a single Model action on your “Open” Model listening for changes on the First Name, Middle Name, or Last Name fields, whose action is to combine those together into the desired concatenated Name format, and put this value into the Name field on the row in question. However, Model Actions are only available via XML in the Mobile Composer — they work fine, but you have to define them in XML. I could suggest how to do this if you are open to it, or we could continue to debug your renderer code.

Smart. I’ll work on that now. We have a desktop version of the page as well, so I’ll create the model actions there and paste them into the mobile XML.

Zach (et al.),

i’m using model actions to set Name to the correct value, instead of a custom renderer. However, I’m struggling to get the field to render again when the field is updated.

skuid.ui.Field(‘Name’).render() ?

Will that render every field on every model called Name?

All affected Name fields should automatically re-render if you update the value of that field on any rows in the Model. Did you remove the custom field renderer snippet from all of the Name fields?

There are no custom renderers on Name.

This is the model action set for when First Name, Middle Name, or Last Name are updated:

However, this is the result after typing in those three fields:

Help?