JSLink and Display Templates Part 3 – Creating a custom editing interface

So this part talks about some of the more interesting bits of Display Templates .. the editing interface. This introduces some new features as not only are we required to provide and rendering all of the editing controls but we also have to somehow get SharePoint to understand what value it should use when someone wants to save their changes.

Now the process for creating an editing interface is identical for both “New” and “Edit” forms (with the exception that the editing interface also needs to deal with loading up existing values) so for this post our examples will focus on the “Edit Form” functionality.

Registering our Edit Form function
So this uses exactly the same technique that we walked through in Part 2, where we register our desired override method for our named field.

(function() {
  var mjhOverrides = {};
  mjhOverrides.Templates = {};

  mjhOverrides.Templates.Fields = {  

    ‘MyCustomField’: {
      ‘NewForm’: mjh.editMethod,
      ‘EditForm’: mjh.editMethod
    }
  };

  SPClientTemplates.TemplateManager.RegisterTemplateOverrides(mjhOverrides );
 })();
So just like before we create ourselves an override object and tell it we want to use the method “mjh.editMethod(ctx)” to render both the “EditForm” and “NewForm” for our field “MyCustomField” and we then register that using the SPClientTemplates.TemplateManager.RegisterTemplateOverrides method.

The Edit Render Method
The format of the rendering method for the edit interface (in this example) is pretty straightforward. I have simply rendered out a drop-down list containing three items.

mjh.editMethod = function (ctx) {
  var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx); 

  formCtx.registerGetValueCallback(formCtx.fieldName, mjh.getFieldValue.bind(null, formCtx.fieldName));

  // items to appear in the drop down list
  var items = new Array(“Item 1”, “Item 2”, “Item 3”);
  var returnHtml = “<div id=” + ctx.CurrentFieldSchema.Name + “><select>”;
 
  for (var i = 0; i < length; i++) {
    returnHtml += “<option”;
    if (ctx.CurrentFieldValue == items[i]) {
      // select the current item if the value matches
      returnHtml += ” selected “;
    }  
    returnHtml += “>” + items[i] + “</option>”;
  }

  returnHtml += “</select></div>”;
  return returnHtml;
};

 

Now as you can see this time we have a new method in play as we are also creating a new “FormContext” object and using the registerGetValueCallback method. This method is what tells SharePoint to use our method to find out what the field value should be when the item is saved. The first argument is the name of the field we are overriding, and the second argument is the method that will return our field value.

We have also made use of the JavaScript “bind” function so that we can specify arguments that should be passed to our callback method, in this case we want to pass the field name (you’ll see why in a minute). 

The only other thing special going on here is that I check to see if the current value of the item matches the option, and if it is we add the “selected” attributed.

We have also enclosed the whole thing in a div using the fieldname as the ID, which we can use in our callback method below …

The Get Value callback
The next thing of course is our method to retrieve the actual field value, and for this we use a little bit of jQuery (you can choose your own way of getting the jQuery library onto the page. Adding it as an extra JSLink URL is quite cool, although if you use jQuery everywhere you might otherwise want to use a Custom Action or Delegate Control so it appears on every page).

mjh.getFieldValue = function (fieldName) {
  // a div used with jQuery to identify the appropriate items 
  var divId = “#” + fieldName;
  // get the selected item 
  var selectedItem = $(divId + ‘ option:selected’)[0];
  // return the value 
  return selectedItem.innerText;
};
So you can see above that we are using the fieldName argument so we can identify the correct div. This allows us to use the same methods on multiple fields without them clashing.
We then simply use a small jQuery statement to pull out the selected item (the “option” element which has an attributed of “selected”) and return the “innerText” (which in our example is the value we want to save). Of course you need to be mindful of the data type of the field you are working with. All values are returned as Text but fields such as People and Lookup Fields need to return a specifically formatted string.
I then bound this to a site column (of type Text) with the following schema:
<Field ID={A424AE9E-1F1D-4ECE-B695-202F5106352E}
  Name=MyCustomField
  DisplayName=My Custom Field
  Description=a text field which has custom rendering?
  Type=Text
  Required=FALSE
  Group=MJH JSLink Columns
  JSLink=~layouts/MJH.JSLink/jquery-1.10.2.min.js|~layouts/MJH.JSLink/MJH.JSLink.js
  Overwrite=TRUE>
</Field>
Once that is all deployed it should look something like this …

My Custom Field – a Text field but rendered as a drop-down list

So that is pretty much all you need to get going with editing of fields. Come back for Part 7 where I share sample code for handling Lookup Fields (and converting them to checkbox lists), cascading dropdowns and generating values by calling AJAX REST queries.

In the meantime you can download the sample code from this example here:
https://sdrv.ms/14KtFgv

Next – Part 4 – Validating user input

  • Martin Hatch

    Yes you can, if you read Part 1 you'd know you can just upload your JS files and reference it from the Web Part Properties 🙂

    Regarding LiveID .. this is running on Blogger (aka Google) and they don't support LiveIDs

  • Nigel

    Hi Martin

    Great Article !

    Can we do this OOTB ie without the use of Visual Studio.

    I have an Office 365 site but the customer has banned anything emanating from Visual Studio.

    PS Why cannot I use my LiveID to comment ?

  • Imir Hoxha

    Very great article. And thanks for the sample code as well.

  • Wes Niemi

    Very helpful article…well written. Thank you. However…I could not get the registerGetValueCallback “bind” to work as the second parameter, like in your example. I had to manually include the function inside the registerGetValueCallback method as the second parameter. Not sure why “bind” is not working?

    • Martin Hatch

      Note that if you refer to a method then it needs to be a publicly callable method (SharePoint is calling it from outside of your own JavaScript code scope)
      I also only use “Bind” when I want to add custom parameters for each item. If the callback doesn’t have specific arguments then you don’t need the explicit “bind” method

      • Wes Niemi

        Thanks for the reply. Looks like you are using the javascript “bind” method here (function.prototype.bind) and passing “null” for the “this” argument, plus appending your own custom parameters as needed. Correct? For some reason, I was thinking the bind method was a SharePoint thing…but looks to be a javascript keyword. thanks again.