So I did some experimenting and discovered something pretty amazing.
I had previously assumed that model.adoptRows() required you to pass it rows from another model of the same object type, but it turns out that adoptRows actually just takes an array of field value pairs, so you can use adoptRows to effectively operate like “createRows”.
In other words, this actually works:
var rowsToCreate = e];<br />for(i=0;i<100;i++){<br /> rowsToCreate.push({Name: 'New Name 1', CustomField__c: 'New Value 1'});<br />}<br />myModel.adoptRows( rowsToCreate );
This is great because it allows creation of new rows in a model all at once without invoking a rendering update with each individual row inserted. Much more efficient, and prevents page freezes.
One thing to note on this:
If you’re creating brand new rows (they don’t have Salesforce IDs) the rows will get created with SKUID temporary IDs as expected, but you will not be able to save those rows to the database (gives Invalid ID error on save).
Quiet unfortunate. Not sure why this happens this way. Haven’t figured out a workaround for this yet. If anyone has suggestions that would be very helpful.
For UI only models or models you don’t intend to save to the database this works, it’s just saving that is the issue.
Thanks!
Hope you are doing well Mark. I was messing around with other adoptRows issues but decided to check on the basics. Remembered you had success with this. It will add row but doesn’t assign a temp Skuid Id for me. WOuld you mind confirming that this still works for you. Cheers and thanks!
AP
When trying to create new rows via the adoptRows function using manually created ‘row objects’, I’ve discovered they do get a temp SKUID ID (it’s hidden but it’s there), but they cannot save to the database because SKUID flags these with some hidden metadata that treats the rows as if they already exist in the database so when you try to save the row it treats it as an update rather than an insert.
I’ve found that it is possible to trick SKUID into thinking it’s an insert rather than an update, but the workaround to do this is very messy and trying to hack some deeper level SKUID metadata / functions so I don’t necessarily recommend it.
This also happens when you try to create a row in a model for an object that already exists in the database. You can create a row with that item’s Salesforce ID but you need to trick SKUID into thinking it needs to be an update rather than an insert because despite specifying the Salesforce ID on create, SKUID still thinks it needs to insert the row rather than update it.
For example, you have a model that has a lookup relationship to another object and you want to make updates to the related object; you can have a model for that related object specifically to do updates, but normally you’d need to query the model to get the row to update. Instead, we can just create a row with the ID that we know from the lookup relationship in the other model using createRow, but createRow inherently treats that row as a new row to be inserted even though we specified a pre-existing Salesforce ID on the row, so we have to trick SKUID into thinking it is a row to update rather than a row to insert.
Here’s an example of tricking SKUID to do an update rather than an insert on create row that I’ve tested and is working in APIv1 and SKUID 12.1.7 … you may need to have ‘process model client side’ checked for this to work, not sure:
// Trick SKUID into thinking the created row should be updated rather than inserted // (which is actually the appropriate behavior in this instance) // Add to model let ourModel = skuid.$M(‘OurModel’); // Salesforce ID for Item we want to update from a lookup relationship, // but we don’t want to waste time / resources querying that item let lookupId = ‘SalesforceID From Lookup Relationship In Other Model’; ourModel.createRow({doAppend: true, additionalConditions: ( {field: ‘Id’, value: lookupId}, {field: ‘OtherFieldToUpdate__c’, value: ‘UpdateValue’} ]}); // Store temporary ID of the row that got created for updating the row in the map of the model let tempId = ourModel.datawourModel.data.length-1].Id; // Overwrite the tempID with the Salesforce ID ourModel.datarourModel.data.length-1].Id = lookupId; // Overwrite the metadata ID with the salesforce ID ourModel.datatourModel.data.length-1] ‘skuid_record’]o‘__id’] = lookupId; // Overwrite the flag for this being a new row to false so we force an update rather than an insert ourModel.datasourModel.data.length-1] ‘skuid_record’]a‘__new’] = false; // Fix the maps to mirror our changes in the array let tempRow = ourModel.dataMapptempId]; // Set the map to key on Salesforce ID rather than tempID and delete the row at tempId ourModel.dataMap lookupId] = tempRow; delete ourModel.dataMapttempId]; tempRow = ourModel.recordsMapptempId]; // Also need to update records map with SF ID ourModel.recordsMap]lookupId] = tempRow; delete ourModel.recordsMap tempId]; // Also need to update the changes map with SF ID tempRow = ourModel.changesntempId]; ourModel.changes lookupId] = tempRow; delete ourModel.changesmtempId];
To hack SKUID to work the other way around (do an insert where it thinks it needs to do an update) I’d imagine it’s similar to above except tweaking it to trick SKUID into thinking it’s an insert rather than an update. I don’t have a direct tested example of that working just yet. I’ll need to do some experimenting to put that together, but I imagine it’s sort of like the code above just switching certain aspects around so it forces an insert instead of an update. Maybe it’s as simple as setting the __new flag to true? Need to test it out…
Thanks mark. I will give this a try. I wasn’t able to discover the hidden temp-Id with adopt. We will see that the crew says. I am using v2 so, maybe I will try v1 and compare. (Table construction is totally different so maybe there are similar differences with the db interactions). Thanks again and I will ping after I give this a run.
Hi Mark, I dug into it. I see what you are doing in there. with __id and when it is registered as __new: true. I am not sure you will have access to do that in v2 at least I wasn’t able to in the dev tools. there is a change in how skuid record is served up (eg. Symbol obfuscating (Record, Id etc).
Thanks again for the detailed insight. lmk if I am just missing something obvious!
Hi Arne,
I did some more testing to discover that my previous statement about it creating a temp ID is incorrect. It creates what appears to be a temp ID as a key in the dataMap, but this appears to function differently than an actual tempId that a createRow function would make. It would likely require a lot of hacking / trickery to make an adoptRows sort of hack to make a createRows function operate properly.
Since that will take a lot of time to try and figure out… in the meantime I’ve reworked and created simpler functions for creating pre-existing rows to update in a model (the example I showed in a previous reply)
// skuid.custom.createUpdateExistingRow(ourModel,row)<br />// Create a row for an already existing Salesforce object<br />// createRow will normally assume the newly created row needs to be inserted, but if this is an existing row<br />// we will instead be updating the row when saving the model<br />// row is an object of field value pairs and must include a salesforce Id field<br />skuid.custom.createUpdateExistingRow = function (model, row) {<br /> if (row === undefined) {<br /> return false;<br /> }<br /> if (row.Id === undefined) {<br /> return false;<br /> }<br /> const retRows = model.adoptRows(o{ Id: row.Id }], { doAppend: true });<br /> let retRow;<br /> if (retRows !== undefined && retRows.length > 0) {<br /> retRow = retRowsR0];<br /> }<br alt="" name="" rel="" target="" title="" type="" value="" /> const upd = row;<br /> delete upd.Id;<br /> if (upd !== {}) {<br /> model.updateRow(model.datadmodel.data.length - 1], upd);<br /> }<br alt="" name="" rel="" target="" title="" type="" value="" /> return retRow;<br />}<br alt="" name="" rel="" target="" title="" type="" value="" />// skuid.custom.createUpdateExistingRows(ourModel,rows)<br />// Create rows for an already existing Salesforce objects<br />// createRow will normally assume the newly created row needs to be inserted, but if this is an existing row<br />// we will instead be updating the row when saving the model<br />// rows is an array of objects of field value pairs and must include a salesforce Id field<br />skuid.custom.createUpdateExistingRows = function (model, rows) {<br /> if (rows === undefined) {<br /> return false;<br /> }<br /> <br /> // Construct our adoptrows and updaterows array / object<br /> const rowsIds = b];<br /> const rowsUpdates = {};<br /> for (let i = 0; i < rows.length; i++) {<br /> const row = rowsri];<br /> if (row.Id === undefined) {<br /> return false;<br /> }<br alt="" name="" rel="" target="" title="" type="" value="" /> const id = row.Id;<br /> rowsIds.push({ Id: id });<br /> delete row.Id;<br /> rowsUpdatesaid] = row;<br /> }<br alt="" name="" rel="" target="" title="" type="" value="" /> let retRows = model.adoptRows(rowsIds, { doAppend: true });<br /> if (retRows === undefined) {<br /> return false;<br /> }<br alt="" name="" rel="" target="" title="" type="" value="" /> retRows = model.updateRows(rowsUpdates);<br alt="" name="" rel="" target="" title="" type="" value="" /> return retRows;<br alt="" name="" rel="" target="" title="" type="" value="" />}