Click here to Skip to main content
15,867,686 members
Articles / Productivity Apps and Services / Sharepoint / SharePoint 2013

SharePoint 2013 Client Side Rendering: List Forms + Layout

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
15 Oct 2015CPOL4 min read 55.2K   440   6   12
Tiny micro-templating engine fully compatible with SharePoint CSR

Introduction

SharePoint CSR for List Forms has two modes: Standard and CustomLayout. Unfortunately, the latter which is intended for forms with custom layouts, doesn't work (and btw, this is still not fixed in SP2016).

I came up with a small JS code snippet that solves this problem and enables creating completely custom form layouts (this works in Standard mode, no need to switch into CustomLayout).

Usage Example

This is the form that will be customized:

Image 1

And this is the template (it is added to the page via Script Editor):

HTML
<div style="display:none" data-role="form">
  <h3>
    <span data-field="Title">City of <strong>{Value}</strong></span>
    (<span data-field="Country">{Value.split(';#')[1]}</span>)
  </h3>
  <hr>
  <div data-field="*" class="my-formfield">
      <label>{Title} <span style="{ Required ? '' : 'display: none' }">*</span></label>
      <span data-role="field-control" />
  </div>
</div>

Then, also on this page is included the 50-lines js file that you'll find below.

And here's the result:

Image 2

There's also some minimal additional CSS that I added to the page along with the template itself:

HTML
<style>
.my-formfield {
   padding-bottom: 4px;
}
.my-formfield > label {
    font-size: 14px;
    width: 115px;
    display: inline-block;
    vertical-align: top;
}
.my-formfield > span {
    display: inline-block;
    vertical-align: top;
}
</style>

Show Me the Code!

Ok, and now, here's the code that processes this template and does the customization:

JavaScript
SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function() {

  function init() {
    var templates = {};
    
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides({

      OnPreRender: function(ctx) {
        if (!ctx.FormContext)
          return;
        var listId = ctx.FormContext.listAttributes.Id;
        var templ = templates[listId] || document.querySelector
        ("[data-list-id='" + listId + "']") || 
        document.querySelector("[data-role='form']");
        if (!templ)
          return;
        if (!templates[listId])
        {
          var table = document.querySelector("#WebPart"+ 
          ctx.FormUniqueId + " .ms-formtable");
          table.style.display = 'none';
          table.parentNode.insertBefore(templ, table);
          templ.style.display = '';
          templates[listId] = templ;
        }
        var field = ctx.ListSchema.Field[0];
        var el = document.querySelector('tr > td > span#'+
        ctx.FormUniqueId + listId + field.Name);
        var target = templ.querySelector("[data-field~='" + 
        field.Name + "']") || templ.querySelector("[data-field='\*']");
        if (target && el && field.Name != "Attachments")
        {
          if (target.attributes['data-field'].value=='*' || 
          target.attributes['data-field'].value.indexOf(' ') != -1)
          {
            target.style.display = 'none';
            var cloned=target.cloneNode(true);
            cloned.setAttribute("data-field", field.Name);
            cloned.style.display = '';
            target.parentNode.insertBefore(cloned, target);
            target = cloned;
          }
          var html = target.innerHTML;
          field.Value = Encoding.HtmlEncode(ctx.ListData.Items[0][field.Name]);
          html = html.replace(/{[^}]+}/g, function(m) { with (field) return eval(m); });
          target.innerHTML=html;
          var control = target.querySelector("[data-role='field-control']");
          control && control.parentNode.replaceChild(el, control);
        }
      }
      
    });
  }

  RegisterModuleInit(SPClientTemplates.Utility.ReplaceUrlTokens
  ("~siteCollection/Style Library/customlayout.js"), init);
  init();

});

The code is pretty straightforward:

  1. Find the template
  2. Bring template next to original form
  3. Hide original form
  4. Show template
  5. Replace stuff in template
  6. Done

Please feel free to change the code to adapt it for your own needs! :)

"Installation"

Copy the code and include it to the page using any method you like. It is also safe to include it in the site scope (e.g. via masterpage or custom action) and use it along with any other CSR code.

If your site has MDS (Minimal Download Strategy) enabled, don't forget you cannot include JavaScript inline, as this breaks MDS. So create a separate js file, put code there, upload the file e.g. to Style Library, and include it to the page e.g. using JSLink of the ListFormWebPart.

Template Documentation

Actually, you can integrate CSR with existing templating engine, but my idea was to create a snippet that doesn't have dependencies and which I could quickly copy-paste into the page and start working. Below is the documentation for that micro-engine.

So element with attribute data-role="form" will be the template. Please also add style="display: none" for better user experience, so that initially the template is hidden.

If you have several forms on one page, add data-list-id attribute and put id of the list there:

HTML
<div style="display:none" data-role="form" 
data-list-id="YOUR-LIST-GUID-HERE">
  <!-- ... -->
</div>

You can insert your HTML template to the page via Script Editor webpart, Content Editor Webpart with an external file as source, or any other way to bring a piece of HTML into the page.

Inside the form template, elements with attribute data-field define scope of the corresponding field. You can also put several field names into one data-field attribute, separated by whitespace (see tabs example below). Fields that are not specifically mentioned anywhere, will be rendered using data-field="*" template.

Notice: Internal field name should be used to identify fields.

Element with attribute data-role="field-control" will be replaced with the field control. The field control is rendered by CSR, so if you want to replace it with your custom control, you can do that using normal CSR approach.

Text in curly brackets will be evaluated against the corresponding field object, which looks like this:

JavaScript
{
  Description: "",
  Direction: "none",
  FieldType: "Text",
  Hidden: false,
  IMEMode: null,
  Id: "FIELD-GUID-GOES-HERE",
  MaxLength: 255,
  Name: "Title",
  ReadOnlyField: false,
  Required: true,
  Title: "Title",
  Type: "Text",
  Value: "Tallin"
}

So you can refer to any of those properties inside curly brackets. Depending on the field type, there may be some additional properties in this object (or some properties may not be there).

Why Not Render the Form Completely From Scratch?

Comparing to rendering the form from scratch, this approach has some important benefits:

  • Native SharePoint form functionality is retained (loading form data, saving, validation, ribbon integration, etc.)
  • This method is CSR-compatible: you can use CSR for customizing field controls as before. The code just adds ability to change forms layout
  • No external dependencies. Just copy-paste and it works.
  • Extremely small amount of code.

Another Example: Tabs

Let's say we have a standard Contacts list. Now it's extremely easy to add tabs to Contacts list form.

CSS + template code + jquery ui dependencies:

HTML
<div data-role="form" style="display:none">
    <div id="my-formtabs">
        <ul>
            <li><a href="#tab-general">General</a></li>
            <li><a href="#tab-contact-info">Contact info</a></li>
            <li><a href="#tab-other">Other</a></li>
        </ul>
        <div id="tab-general">
            <div data-field="Title FirstName Company JobTitle" 
            class="my-formfield">
                <label>{Title} <span style="{ Required ? 
                '' : 'display: none' }">*</span></label>
                <span data-role="field-control" />
            </div>
        </div>
        <div id="tab-contact-info">
            <div data-field="Email CellPhone 
            WorkAddress WorkState WorkCountry" class="my-formfield">
                <label>{Title} <span style="{ Required ? 
                '' : 'display: none' }">*</span></label>
                <span data-role="field-control" />
            </div>
        </div>
        <div id="tab-other">
            <div data-field="*" class="my-formfield">
                <label>{Title} <span style="{ Required ? '' : 
                'display: none' }">*</span></label>
                <span data-role="field-control" />
            </div>
        </div>
    </div>
</div>

<!-- CSS -->
<style>
.my-formfield {
   padding-bottom: 4px;
}
.my-formfield > label {
    font-size: 14px;
    width: 115px;
    display: inline-block;
    vertical-align: top;
}
.my-formfield > span {
    display: inline-block;
    vertical-align: top;
}
</style>

<!-- Jquery & Jquery UI -->

<link rel="stylesheet" 
href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script type="text/javascript">
  document.write('<script 
  src="//code.jquery.com/jquery-1.10.2.js"><'+'/script>');
  document.write('<script 
  src="//code.jquery.com/ui/1.11.4/jquery-ui.js"><'+'/script>');
</script>

<script type="text/javascript">
  $('#my-formtabs').tabs();
</script>

Notice: Of course, if you have MDS-enabled site, you shouldn't use inline code.

The result:

Image 3

Further Reading

Check out my other articles about CSR:

Conclusion

CSR is not perfect, but... it's JavaScript! So even if it doesn't support something, it's always possible to extend it and resolve the problem. 50 lines of code presented in this article enable custom layouts for CSR list forms.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Finland Finland
Full stack developer, enterprise web software. Microsoft MVP, open source person, speaker, online expert.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Member 1419152921-Mar-19 14:25
Member 1419152921-Mar-19 14:25 
SuggestionYo, I forked your code. Pin
Benjamin Warren17-Aug-17 20:52
Benjamin Warren17-Aug-17 20:52 
QuestionChange Display Name of Field in Quick Edit View in Using Client Side Rendering in SharePoint 2013 Pin
Member 1295366316-Jan-17 21:14
Member 1295366316-Jan-17 21:14 
PraiseThank you! thank you! thank you! Pin
iubi_kat21-Jul-16 3:22
iubi_kat21-Jul-16 3:22 
GeneralRe: Thank you! thank you! thank you! Pin
Andrei Markeev12-Oct-16 9:58
Andrei Markeev12-Oct-16 9:58 
QuestionFeed back of a use case Pin
Member 1241921028-Mar-16 12:13
Member 1241921028-Mar-16 12:13 
AnswerRe: Feed back of a use case Pin
Andrei Markeev20-Jul-16 13:54
Andrei Markeev20-Jul-16 13:54 
GeneralRe: Feed back of a use case Pin
Member 124192101-Aug-16 22:24
Member 124192101-Aug-16 22:24 
QuestionEncoding is undefined Pin
VladimirOrl7-Jan-16 21:54
VladimirOrl7-Jan-16 21:54 
AnswerRe: Encoding is undefined Pin
Member 120200147-Sep-16 21:04
Member 120200147-Sep-16 21:04 
GeneralRe: Encoding is undefined Pin
Andrei Markeev12-Oct-16 10:22
Andrei Markeev12-Oct-16 10:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.