Should condition value be applied at Save, or when row is created?

I’m building a page and encountered some strangeness with Models, and have isolated the problem in a demo page. I’ll try and add the XML for this page into this post - if it doesn’t work, I’ll host elsewhere and link in the comments. It should work in any vanilla org with Accounts and Contacts.

There are two models - Account and Contacts. The idea is you can create an Account and Contacts for that account at the same time. As it’s a demo page, it’s a little weird, but essentially you enter an Account name at the top, then enter Contact email addresses in a table underneath. A button at the top Saves the Account first, then Contacts.

The Contacts model has a condition that sets the LastName field to the value from the Account Name - weird, but this is for demo purposes, so please bear with me :slight_smile:

The idea here is that when saving the Contacts, the Account name should get pulled in and put into each Contact’s Last Name. This should be similar in principle to how I can link newly created Contacts to a newly created Account all in the same page, where the Contacts has a condition that sets AccountID to the ID field of the account. Skuid does the magic here.

But it doesn’t work like this for non-ID fields. In this case, the Last Name only gets set if the Account name is entered and a row is created in the model after this - and the value is only set on the new model, not any that existed before the Account Name was set (I’d be OK with this so long as on save, the value was copied, but that doesn’t seem to happen).

Similarly, if I create a new row in the Contacts model with the Javascript API, if Account Name is populated it ends up on the Contact record (I imagine that the + button in the table is calling createRow() in the background).

To demo this with the page, enter an Account name, enter an email address for the default row in the table, then click the + icon to add another row, put another email address in, and then click the button at the top. You should receive an error, but check the account that got created - the second contact was created with the last name set.

Am I wrong in my thinking of the way this should work? I have a workaround for now, but just curious! Here’s the code:

<skuidpage unsavedchangeswarning="yes" showsidebar="true" showheader="true"> <models> <model id="Account" limit="" query="false" createrowifnonefound="true" sobject="Account" doclone="" type=""> <fields> <field id="Name"/> </fields> <conditions/> <actions/> </model> <model id="Contacts" limit="" query="false" createrowifnonefound="true" doclone="" type="" sobject="Contact"> <fields> <field id="Email"/> <field id="LastName"/> </fields> <conditions> <condition type="modelmerge" value="" field="AccountId" operator="=" model="Account" enclosevalueinquotes="true" mergefield="Id" novaluebehavior="deactivate"/> <condition type="modelmerge" value="" field="LastName" operator="=" model="Account" enclosevalueinquotes="true" mergefield="Name" novaluebehavior="deactivate"/> </conditions> <actions/> </model> </models> <components> <pagetitle model="Contacts"> <maintitle> <template>{{Name}}</template> </maintitle> <subtitle> <template>{{Model.label}}</template> </subtitle> <actions> <action type="multi" label="New Button"> <actions> <action type="save"> <models> <model>Account</model> <model>Contacts</model> </models> </action> </actions> </action> </actions> </pagetitle> <basicfieldeditor showheader="true" showsavecancel="false" model="Account" buttonposition="" mode="edit" layout=""> <columns> <column width="100%"> <sections> <section title="Section A"> <fields> <field id="Name" valuehalign="" type=""/> </fields> </section> </sections> </column> </columns> </basicfieldeditor> <skootable showconditions="true" showsavecancel="false" searchmethod="server" searchbox="false" showexportbuttons="false" pagesize="10" createrecords="true" model="Contacts" buttonposition="" mode="edit" emptysearchbehavior="query"> <fields> <field id="Email"/> </fields> <rowactions> <action type="edit"/> <action type="delete"/> </rowactions> <massactions usefirstitemasdefault="true"> <action type="massupdate"/> <action type="massdelete"/> </massactions> <views> <view type="standard"/> </views> <searchfields/> </skootable> </components> <resources> <labels/> <javascript/> <css/> </resources> </skuidpage>

This is an interesting problem. 

When you create the rows for the two models there is no data in the Account Name - and so the model merge condition you built into the Contact model fails.  These conditions do not update in real time.  You have to instruct skuid to create the Contact row after the Account data has been filled in. 

So, what I’d reccomend is the following:
1. Only create the Account row on page load. 
2. Add a “model action” to the account model that is triggered on row changes to the Account Name field. 
3. The result of that action should create the row on contact model and populate a default value of the Name field from the Account model. 

I think that will take care of your issue. 

PS.  I appologize that my response is nowhere near as thorough as your post.  Thanks for the narrative! 

Hi Rob, no need to apologise, I love the speedy response!

Agreed on the alternative approach - however, I guess I’d like some confirmation that the magic that Skuid performs only works on reference fields (and possibly a note in the docs to that effect?). Skuid will take care of putting the account’s ID into the Contact records on save, but not other types of field.

Sorry to digress but your solution actually raises another question (possibly should raise this separately but here goes anyway :slight_smile:

Your model action idea will work, however, what is Skuid’s position on the performance of this? My understanding is that this action fires at every update on the account, whether it’s the update we’re interested in or not. For example, we may be showing several account fields, but only want the action to run when one of them updates. Also, my investigations show that the actions run after every keypress (though reference fields act slightly differently), whereas it really only needs to run on tab out.

This seems like it would be inefficient, but I’ve not tested Skuid across as many devices as you and the team probably have :slight_smile: There are alternatives (i.e. Javascript); but on the other hand, many Javascript frameworks nowadays do 2-way data binding. If this was an issue for those frameworks, I imagine the web dev community would have had something to say by now. Therefore, although it may seem inefficient, what Skuid does is really not any worse than what the frameworks do, then using an alternative is overkill, and using actions like this is a fine approach.

Happy to break this out into a separate question if appropriate!

Two matters here. 
1. I’m not sure I get what your statement about “Only Reference” fields means.  Reference fields are the only kind of field where new record models get “proto ids” that are used to tie related data together.  On save the primary object is saved - its “true Id” returned and this is inserted in place of the “proto id’s” in related tables.  This is not really necessary for other data types as there is no relationship to be managed.  However if you want to prepopulate other fields so you can save on data entry - it is totally possible.  You can either add “default row” definition on the “create row action”  or you can use model conditions to prepopulate data as new rows are created. 

2. You can focus the “on row change” model action to a particular field (In the newest release - what are you running?).  Your comments about efficency are of concern to us, which is why we implemented the field listener in addition to the model change listener.  

On the other hand,  all the situations within skuid where actions are taken on typing occur on keypress.  There is lots of listeneing and reacting going on within the javascript code.  You will see queries get resubmitted as you add keys to a search box,  the save button will activate as you add a single keystroke to a text field, etc.  You might be careful not to kick off too many server side processes with this method,  but create new row is a client side process and should be pretty quick.  

An alternative would be to put a button on the page that was rendered after the account was populated and let the user ask to create new contacts. 

And another thought, which might be better all together.  You might show the contact form on the page without any account field (so the user assumes the account is what they just added above).  Then the Save button would have multiple actions… Something like this. 
 - Save Account Model
 - Update rows on Contact model with Account ID from the newly saved Account Model
 - Save Contact Model. 

Once again - with Skuid there are many ways to work the problem…   Hope one gets what you are after. 

Hi again Rob,

You got my point with number 1 - I guess my broader point was that using conditions for default values is a little confusing for newcomers (the original issue wasn’t mine - I wouldn’t have implemented it that way, but I could see why the person would think their approach would work), hence the comment about adding a note in the docs.

And yes, a lot of good options in the second part of your comment - hopefully of help to someone reading this in the future! I hadn’t seen “run action on field update” addition - nice touch! Thanks again for taking the time to respond.

No worries.  Thanks for the feedback.  We are always looking for ways to be clearer in our language and documentation.