Super cool clone snippet

So here’s the deal, I often have to clone rows in a table via Javascript. Some purist would argue that it should be done via Apex (and I agree), but I’ve been told to use Javascript. Eventually it was getting annoying to write all of these various snippets for various objects that pretty much did the same thing. I decided to outsource the snippet to a static resource and call it with the various differences passed in as arguments. I registered a snippet called “clone”.

// utility snippet for easy cloning of rows. arg[0] = row/model etc. arg[1] = other model api name arg[2] = JS Obj with name -> value pairs 
skuid.snippet.registerSnippet('clone',function(){
//this is beautiful code - JA
console.log(arguments);
var params = arguments[0],
    item = params.item,
    dataRow = params.row,
    dataModel = params.model;
    $ = skuid.$;
    console.log(arguments);
var modelName = arguments[1];//pass in the other model name as the second arg
var customMap = arguments[2] || {};//custom mapping to map in the clone as key-value pairs
if(!modelName){
    console.log("ERROR! You have to pass in the model name as the secong arg");
    return;
}
var newDataModel = skuid.$M(modelName),
    newDataRow = newDataModel.createRow();
var used__r = [];
var rowUpdates = {};
//__r fields are tricky and have to be handled specially
function handle__r(field){
    if(field.indexOf('__r') != -1){
        var api = field.split(".")[0];
        if(used__r.indexOf(api) == -1){
            rowUpdates[api] = dataRow[api];
        }
        used__r.push(api);
    }
}
//update the fields that are actually editable
var allFields = dataModel.fields;
for (var i = 0; i < allFields.length; i++) {
    var apiName = allFields[i].id;
    if(customMap[apiName]){
        rowUpdates[apiName] = customMap[apiName];
    }
    else if(dataRow[apiName]){//if we don't have a value don't bother mapping
        handle__r(apiName);
        rowUpdates[apiName] = dataRow[apiName];
    }
}
//update the row with all of our updates
newDataModel.updateRow(newDataRow, rowUpdates);
newDataModel.save();
}); 

Then I call this snippet as a row action, on a table.

var params = arguments[0], $ = skuid.$;
var snip = skuid.snippet.getSnippet('clone');
snip(arguments[0], "LiveMP");

“LiveMP” is the model to clone into. If I want it cloned into the same model, I can just pass in the model name itself as the second param. But here’s the thing, how do I specify the one or two fields that I want to be different (which is usually what happens when your’re cloning something…)??? The answer… pass in a third parameter of key->value pairs that should be treated differently!! Now everything is awesome. I can call my snippet with a third param.

$('#listInPopup li').dblclick(function(){    $.blockUI({
        message:'Splitting...',
        timeout: 1500
    });
    var selectedCampaign = myObj[$(this).text()];
    var clone = skuid.snippet.getSnippet('clone');
    var modelName = "LiveMP";
    var campaignObj = {
      Campaign__c: selectedCampaign  
    };
    clone(params, modelName, campaignObj);
    skuid.$('.ui-dialog-content').dialog('close');
});

Just wanted to share this, I think it’s pretty cool.

Thanks for sharing Moshe. 

Great work as always, Moshe!

Remove the line “item = params.item,” (which you’re not using anyway) and you can run this from a pagetitle button as well.

I added a jquery deferred promise as well, to be able to call your clone function as part of a action framework sequence.

&#47;&#47; utility snippet for easy cloning of rows&#46; arg[0] = row/model etc&#46; arg[1] = other model api name&#46; arg[2] = JS Obj with name -&gt; value pairs 'clone': function(){<br />var params = arguments[0],<br /> &nbsp; &nbsp;dataRow = params&#46;row,<br /> &nbsp; &nbsp;dataModel = params&#46;model;<br /> &nbsp; &nbsp;$ = skuid&#46;$,<br /> &nbsp; &nbsp;dfd = new $&#46;Deferred();<br /> &nbsp; &nbsp;console&#46;log(arguments);<br />var modelName = arguments[1]; &#47;&#47;pass in the other model name as the second arg<br />var customMap = arguments[2] || {}; &#47;&#47;custom mapping to map in the clone as key-value pairs<br />if (!modelName) {<br /> &nbsp; &nbsp;console&#46;log("ERROR! You have to pass in the model name as the secong arg");<br /> &nbsp; &nbsp;return;<br />}<br />var newDataModel = skuid&#46;$M(modelName),<br /> &nbsp; &nbsp;newDataRow = newDataModel&#46;createRow();<br />var used__r = [];<br />var rowUpdates = {};<br />&#47;&#47;__r fields are tricky and have to be handled specially<br />function handle__r(field){<br /> &nbsp; &nbsp;if(field&#46;indexOf('__r') != -1){<br /> &nbsp; &nbsp; &nbsp; &nbsp;var api = field&#46;split("&#46;")[0];<br /> &nbsp; &nbsp; &nbsp; &nbsp;if(used__r&#46;indexOf(api) == -1){<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rowUpdates[api] = dataRow[api];<br /> &nbsp; &nbsp; &nbsp; &nbsp;}<br /> &nbsp; &nbsp; &nbsp; &nbsp;used__r&#46;push(api);<br /> &nbsp; &nbsp;}<br />}<br />&#47;&#47;update the fields that are actually editable<br />var allFields = dataModel&#46;fields;<br />for (var i = 0; i &lt; allFields&#46;length; i++) {<br /> &nbsp; &nbsp;var apiName = allFields[i]&#46;id;<br /> &nbsp; &nbsp;if(customMap[apiName]){<br /> &nbsp; &nbsp; &nbsp; &nbsp;rowUpdates[apiName] = customMap[apiName];<br /> &nbsp; &nbsp;}<br /> &nbsp; &nbsp;else if(dataRow[apiName]){ &#47;&#47;if we don't have a value don't bother mapping<br /> &nbsp; &nbsp; &nbsp; &nbsp;handle__r(apiName);<br /> &nbsp; &nbsp; &nbsp; &nbsp;rowUpdates[apiName] = dataRow[apiName];<br /> &nbsp; &nbsp;}<br />}<br />&#47;&#47;update the row with all of our updates<br />newDataModel&#46;updateRow(newDataRow, rowUpdates);<br />$&#46;when(newDataModel&#46;save())<br />&#46;done(function(){<br />dfd&#46;resolve();<br />})<br />&#46;fail(function(){<br />dfd&#46;reject();<br />console&#46;log('target model of cloned row failed to save&#46;');<br />});<br />return dfd&#46;promise();<br />}