Saving dynamic model doesn't update server.

Hey Matt -

I believe I’ve found the source of your issue and along the way found another issue that you might be running in to.

First, let’s start with the root cause of why the server isn’t updating. In your code, you are not calling skuid.model.load. The result of this is that skuid doesn’t have the metadata necessary to appropriately handle the updateRows call. If you run the test I suggested above, I’m fairly certain that you will see that no network call is made after calling “save”. By adding the following line of code after you register the interactionUpdate model, you should see your data update on the server:

skuid.model.load([patientCase, interactionUpdate])

In troubleshooting your issue, I ran in to a problem with model conditions, see enclosevalueinquote condition parameter remoting exception (Banzai 7.12) for more details.

Per the above, if you are running Skuid 7.x, you will want to change your condition attribute to encloseValueInQuotes

Since I didn’t have your custom objects, in order to troubleshoot this, I created a similar page using Accounts and Contacts. I’ve included that page below so you can take a look. Please forgive the refactoring of your original code, as I wrote the test page, it was easier for me to break up things as I figured out what you were attempting to do. Hopefully what I came up with is close :slight_smile:

<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="true" showheader="true" tabtooverride="Account"> <models> <model id="Contact" limit="20" query="true" createrowifnonefound="false" adapter="" type="" sobject="Contact" doclone=""> <fields> <field id="FirstName"/> <field id="Name"/> <field id="LastName"/> <field id="Description"/> <field id="AccountId"/> <field id="Account&#46;Name"/> </fields> <conditions> <condition type="param" value="id" field="Id" operator="=" enclosevalueinquotes="true" novaluebehavior=""/> </conditions> <actions/> </model> </models> <components> <pagetitle uniqueid="sk-3u-sd-81" model="Contact"> <maintitle> <template>{{Name}}</template> </maintitle> <subtitle> <template>{{Model&#46;label}}</template> </subtitle> <actions> <action type="multi" label="Save" icon="sk-icon-save"> <actions> <action type="save" rollbackonanyerror="true"> <models> <model>Contact</model> </models> </action> </actions> </action> <action type="multi" label="Cancel" icon="sk-icon-cancel"> <actions> <action type="cancel"> <models> <model>Contact</model> </models> </action> </actions> </action> </actions> </pagetitle> <basicfieldeditor showheader="true" showsavecancel="false" showerrorsinline="true" model="Contact" buttonposition="" uniqueid="sk-3COBx-1173" mode="read"> <columns> <column width="100%"> <sections> <section title="Section A" collapsible="no"> <fields> <field id="Name" valuehalign="" type=""/> <field id="FirstName"/> <field id="LastName"/> <field id="AccountId"/> <field id="Description"/> </fields> </section> </sections> </column> </columns> <renderconditions logictype="and"/> </basicfieldeditor> </components> <resources> <labels/> <css/> <javascript> <jsitem location="inline" name="newInlineJS" cachelocation="false" url=""> (function(skuid){ var $ = skuid&#46;$ , counter = 0; &#47;&#47; creates an object map of the property specified by objectKeyPropName &#47;&#47; from each object in the array specified by items var createMapForArray = function(items, objectKeyPropName) { return items&#46;reduce(function(obj, k) { var key = k[objectKeyPropName]; obj[key] = k; return obj; }, {}); }; &#47;&#47; creates an object map of model id to model &#47;&#47; for each model that is for SObject Contact var getcontactModelMap = function (models) { var contactModels = models&#46;filter( function(model) { return model&#46;objectName === 'Contact'; }); return createMapForArray(contactModels, 'id'); }; var getRowsToUpdate = function(contactModel, fieldUpdates) { var rowsToUpdate = {}; &#47;&#47; Update description for all contacts to the website of the account plus the /s# $&#46;each(contactModel&#46;getRows(), function(i, row) { rowsToUpdate[row&#46;Id] = fieldUpdates; }); return rowsToUpdate; }; &#47;&#47; create a dynamic account model var createAccountModel = function() { var accountModel = new skuid&#46;model&#46;Model(); accountModel&#46;objectName = 'Account'; accountModel&#46;id = 'DynamicAccount'; accountModel&#46;recordsLimit = 1; accountModel&#46;fields = [ { id: 'Id' } , { id: 'Website' } , { id: 'CreatedDate' } ]; accountModel&#46;conditions = [ { type: 'fieldvalue' , field: 'Id' , operator: '=' , value: '' , state: 'filterableoff' , inactive: true , name: 'AccountId' , encloseValueInQuotes: true } ]; accountModel&#46;initialize()&#46;register(); return accountModel; }; var createContactModel = function() { &#47;&#47;Create model on Interaction for updating Pregnancy Intention var contactModel = new skuid&#46;model&#46;Model(); contactModel&#46;objectName = 'Contact'; contactModel&#46;id = 'DynamicContact'; contactModel&#46;recordsLimit = 50; contactModel&#46;fields = [ { id: 'Id'} , { id: 'Description' } , { id: 'CreatedDate' } , { id: 'LeadSource'} , { id: 'AccountId'} , { id: 'Name' } ]; contactModel&#46;conditions = [ { type: 'modelmerge' , field: 'AccountId' , operator: '=' , model: 'DynamicAccount' , mergeField: 'Id' , inactive: false , encloseValueInQuotes: true , noValueBehavior: 'noquery' } &#47;&#47; NOTE - The following conditions are commented out to make it easier to find contacts &#47;&#47; but Matt's original code did have a condition for a picklist field &#47;&#47; , { &#47;&#47; type: 'fieldvalue' &#47;&#47; , field: 'LeadSource' &#47;&#47; , operator: '=' &#47;&#47; , value: 'Web' &#47;&#47; , state: 'on' &#47;&#47; , inactive: false &#47;&#47; , encloseValueInQuotes: true &#47;&#47; } , { type: 'modelmerge' , field: 'CreatedDate' , operator: 'gte' , model: 'DynamicAccount' , mergeField: 'CreatedDate' , inactive: false , encloseValueInQuotes: false } ]; contactModel&#46;initialize()&#46;register(); return contactModel; }; &#47;&#47; find the account id for the first contact &#47;&#47; that has an account id var findAccountId = function(models) { for (var i = 0; i &amp;lt; models&#46;length; i++) { var contactRow = models[i]&#46;getFirstRow(); if (contactRow &amp;amp;&amp;amp; contactRow&#46;AccountId) { return contactRow&#46;AccountId; } } return null; }; &#47;&#47; get the list of models that are being saved &#47;&#47; that were identified in our list of Contact models var getContactModels = function(savedModels, contactModelMap) { &#47;&#47; Find all saved Contact models var savedContactModels = []; $&#46;each(savedModels, function(idx, model) { if (contactModelMap&#46;hasOwnProperty(model&#46;id)) { savedContactModels&#46;push(this); } }); return savedContactModels; }; $(document&#46;body)&#46;one('pageload',function(){ &#47;&#47; get map of Contact models var contactModelMap = getcontactModelMap(skuid&#46;model&#46;list()); &#47;&#47; build array of Contact Models var contactModels = $&#46;map(contactModelMap, function(model, modelId) { return model; }); &#47;&#47; if there are contact models, create an account &amp;amp; contact models and subscribe to Skuid's save event if (contactModelMap &amp;amp;&amp;amp; !$&#46;isEmptyObject(contactModelMap)) { var accountModel = createAccountModel(); var contactModel = createContactModel(); &#47;&#47; make sure we load 'em up skuid&#46;model&#46;load([accountModel, contactModel]); &#47;&#47;Subscribe to the model save event&#46; skuid&#46;events&#46;subscribe('models&#46;saved', function(saveResult){ &#47;&#47; Only run if the initiator was a ui element (to eliminate loop) if (saveResult&#46;initiatorId) { &#47;&#47; check the models that were saved and see if any where from our Contact model list var savedContactModels = getContactModels(saveResult&#46;models, contactModelMap); &#47;&#47; If any contact models were saved&#46;&#46;&#46; if (savedContactModels&#46;length) { var dfd = new $&#46;Deferred(); &#47;&#47; find the account id to use var accountId = findAccountId(savedContactModels); &#47;&#47; if we have an account id if (accountId) { &#47;&#47; set the account model condition accountModel&#46;setCondition(accountModel&#46;getConditionByName('AccountId'), accountId); &#47;&#47; update the account model and contact model $&#46;when(skuid&#46;model&#46;updateData([accountModel, contactModel]))&#46;then(function() { &#47;&#47; get the first row of the account and then &#47;&#47; build the new website name var acctRow = accountModel&#46;getFirstRow() , website = (acctRow &amp;amp;&amp;amp; acctRow&#46;Website) || 'http:&#47;&#47;www&#46;test&#46;com' , newWebsite = (website + '/s' + (counter++)); &#47;&#47; get the rows to update var rowsToUpdate = getRowsToUpdate(contactModel, { Description: newWebsite }); &#47;&#47; update the rows in the contact model contactModel&#46;updateRows(rowsToUpdate); &#47;&#47; Save updates to server $&#46;when(contactModel&#46;save()) &#46;done(function() { console&#46;log('Successfully saved contact updates&#46;'); &#47;&#47; reload data for all contact models skuid&#46;model&#46;updateData(contactModels)&#46;then(function() { console&#46;log('updated all contact models'); dfd&#46;resolve(); }); }) &#46;fail(function() { dfd&#46;reject(); console&#46;log('Interaction_UpdateIntention model save failed&#46;'); }); }); } } return dfd&#46;promise(); } }); } }); })(skuid);</jsitem> </javascript> </resources> <styles> <styleitem type="background" bgtype="none"/> </styles> </skuidpage>