Copying SharePoint List Items

Most list items tend to be pretty simple, usually consisting of a few fields with some content. So for users to recreate them, it does not take a lot of work. But sometimes I use a list to collect a lot of information in lengthly text fields, and in those cases it would be nice to allow users to copy the contents from another item as a template.

For example, imagine you have a project initiation form or a project charter. We could collect project initiation information for proposed projects in a single list, then use approval workflows for them and sort them by expected value the project would offer the business (such as NPV).

For this example, I created project initiation form and added the following fields:

  • Project Title
  • Project Description
  • Business Case
  • Stakeholders
  • Risks
  • Budget Estimate
  • Expected Value

As you can see, this can end up being a lot of typing (or copying & pasting) for a user. But some projects might be very similar to others, and for those it would be handy to start a new form by copying the contents from a previous form.

You can do it easy enough by workflow, but this would copy and create the item before the user edited its contents. The experience I want is to populate the new item form with content copied from a specified item, and then allow the user to edit the form before creating the item and adding it to the list.

Adding JavaScript to the new item form would allow me to look-up the values for fields from the item I want to copy, and then populate those fields on the new item form. To identify which item to copy from, I passed a query string parameter, CopySourceId, and passed the identifier.

First I created a Custom Action for the list items using SharePoint Designer. This added a menu option to copy the item to a new charter. Then I specified the Navigate to URL property and supplied the URL to the new item form. To pass which item to copy the data from, I appended “&CopySourceId={ItemId}” to the navigation url.
Custom-Action

With the custom action added and passing the source identifier for the item to copy from, next I edited the New Item page to add JavaScript. The JavaScript will use the client side object model to read fields I specify from the item and copy the values to the new form.

I edited the new item page and added a Script Editor web part below the form.
Script-Editor

Inside the Script Editor, I included a reference to a javascript file in the Site Assets folder called CopyCharter.js.
Embed-Script

I created the CopyCharter.js file using the following JavaScript and uploaded it to the Site Assets library.

  • The first function (copyCharter) detects the presence of CopySourceId in the query string and creates the client context to look-up that item if present.
  • The second function (getParameterByName) is a helper function I found to get a query string parameter’s value.
  • The third function (onDataReceived) names each field I want to copy and the form field identifier for where to copy it.
  • The fourth function (copyFieldDataToFormField) is a helper function to look-up each field’s data and write it to the form.
function copyCharter(){
 var sourceId = getParameterByName('CopySourceId');
 if (sourceId == 0) return;

 var clientContext = SP.ClientContext.get_current();
 // Set the list title
 var list = clientContext.get_web().get_lists().getByTitle('Project Charter');
 this.copyItem = list.getItemById(sourceId);

 clientContext.load(this.copyItem);
 clientContext.executeQueryAsync(
 Function.createDelegate(this, onDataReceived),
 function(sender, args) {}
 );
}
_spBodyOnLoadFunctionNames.push("copyCharter()");

function getParameterByName(name) {
 name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
 var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
 results = regex.exec(location.search);
 return results === null ? "0" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

function onDataReceived(sender, args){
 var TEXT = "Text";
 var MULTITEXT = "MultiText";

// Set the form and item field names to the appropriate values
 copyFieldDataToFormField("Title_fa564e0f-0c70-4ab9-b863-0177e6ddd247_$TextField", "Title", TEXT);
 copyFieldDataToFormField("Description_8b07cb26-73c9-446e-8072-c736055359a0_$TextField_inplacerte", "Description", MULTITEXT);
 copyFieldDataToFormField("BusinessCase_a2c862f2-134b-473e-8819-631dcdc28b1b_$TextField_inplacerte", "BusinessCase", MULTITEXT); 
 copyFieldDataToFormField("Stakeholders_98b54755-4832-4e8d-aece-a96520c63689_$TextField_inplacerte", "Stakeholders", MULTITEXT);
 copyFieldDataToFormField("Risks_e42b1ca7-9d92-4228-aee4-208e77aa519d_$TextField_inplacerte", "Risks", MULTITEXT);
}

function copyFieldDataToFormField(formFieldName, itemFieldName, fieldType){
 var formField = document.getElementById(formFieldName);
 if (formField != null){
  var copyField = this.copyItem.get_item(itemFieldName);
 if (copyField != null){
 if (fieldType == "Text")
   formField.value = copyField;
 else if(fieldType == "MultiText")
   formField.innerHTML = copyField;
 }
 }
}

Note: I found the form field name for each item using the DOM Explorer in the IE Developer Tools. I just selected the item I was interested in and copied its ID attribute to pass to the copyFieldDataToFormField function.
DOM-Explorer