Click here to Skip to main content
11,505,486 members (57,506 online)
Click here to Skip to main content

SharePoint 2013 Client Side Rendering: List Views

, 24 Aug 2014 CPOL 29.1K 12
Rate this:
Please Sign up or sign in to vote.
All you need to know to start creating your own CSR customizations in SharePoint 2013.

Introduction 

In SharePoint 2013, Client Side Rendering (aka CSR) is used for rendering list views, list forms and search results. This article provides a head-start into the CSR API for list views: how CSR works, how you can use the API, and the code examples, those you can adapt for your own solutions. 

How CSR works

Unlike previous SharePoint rendering systems (XSLT in 2010 and CAML in 2007), CSR is client-side. The only thing server-side webparts do is they put a huge bulk of raw data into the page, in JSON format. This data become JS object when the page loads, and from then on the Client Side Rendering begins. 

So basically, what CSR does is it gets the JS object with raw data as input, and renders huge HTML string based on it: 

 

After HTML string is fully formed, it is inserted into the DOM.

CSR processing of the raw data is divided into stages, each represented by one overridable JS function. Each function returns its own chunk of HTML. Stages are often nested into each other. 

The stages order isn't documented, so I had to dive head first into the clienttemplates.debug.js file to figure it out. For list views, the order turns out to be the following: 

 

Group, Item and Field functions can be called many times, while View, Header, Body and Footer are called only once. 

Visually it looks like this: 

 

Stage-functions can be overriden with custom functions, thus it really helps to have this picture around when planning customizations. 

Also, there are two additional events that can be used for customization: OnPreRender and OnPostRender. These are not the part of the main process: they don't yield HTML chunks, but rather behave as ordinary events, so you can subscribe to them and execute some code at a specific moment. 

OnPreRender and OnPostRender events are shown on the full CSR diagram below: 

 

As you can see, OnPostRender is particularily useful, because it fires after the formed HTML string is inserted into DOM, so that this is the earliest moment when you can manipulate the DOM elements that were rendered by CSR. 

Using CSR API 

Main entry point of the CSR API is the following function: 

SPClientTemplates.TemplateManager.RegisterTemplateOverrides(options)

The options parameter is a JS object that contains all the necessary information for customizations. It has the following core structure:

var options = {
  OnPreRender: /* function or array of functions */,
  Templates: {
    View: /* function or string */,
    Body: /* function or string */,
    Header: /* function or string */,
    Footer: /* function or string */,
    Group: /* function or string */,
    Item: /* function or string */,
    Fields: {
      'Field1 Internal Name': {
          View: /* function or string */,
          EditForm: /* function or string */,
          DisplayForm: /* function or string */,
          NewForm: /* function or string */
      },
      'Field2 Internal Name': {
          View: /* function or string */,
          EditForm: /* function or string */,
          DisplayForm: /* function or string */,
          NewForm: /* function or string */
      },
      // .... and so on
    }
  },
  OnPostRender: /* function or array of functions */
};

As you can see, this structure resembles the CSR stages and events. 

Now, if I want to subscribe for the OnPreRender and OnPostRender events, I do it like this: 

SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  OnPreRender: function() { console.log('CSR OnPreRender'); },
  OnPostRender: [
    function() { console.log('CSR OnPostRender'); },
    function() { alert('CSR OnPostRender'); }
  ]
});

OnPreRender and OnPostRender accept either a function or an array of them. All provided functions will be executed whenever event is fired. 

Stage-related fields inside Templates field accept a function or a string. For example, let's add some text to the footer of the list view: 

SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  Templates: {
    Footer: "Hello world from <#= ctx.ListTitle #>!"
  }
});

Notice the <#= ... #> tag inside the string! It automatically gets replaced with appropriate value from the context object. Context object ctx is the very object with raw data that was rendered by server-side webparts.

Result of applying this customization:

  

As you can see, the Hello world string appeared in the footer of the list view, and also the token got replaced with the actual value (i.e. the list title).

Instead of string, function can be used for creating the same customization:

SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  Templates: {
    Footer: function(ctx) {
      return "Hello world from " + ctx.ListTitle + "!";
    }
  }
});

So as you can see, the function should accept the context object as the only parameter, and return the HTML string. In most cases, context object is the only parameter, but rarely, there might be additional parameters. For example, Group template receives 7 arguments.

Notice that we cannot use the <#= ... #> tokens any more, at least directly.

As you might expect, there is a lot of string generation happening in CSR, thus I find it very convenient to leverage ASP.Net Ajax String.format function for that purpose. It has same syntax as the well known String.Format from C#. ASP.Net Ajax library is deployed on every SharePoint page by default through the ScriptManager control, so you don't have to worry about that.

Previous example becomes a bit cleaner with String.format: 

SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  Templates: {
    Footer: function(ctx) {
      return String.format("Hello world from {0}!", ctx.ListTitle);
    }
  }
});

Now, please don't forget that RegisterTemplateOverrides call causes out-of-the-box function to be replaced by the custom function. So if you replace something, you have to understand that some functionality may be broken.

For example, if instead of Footer, we use Body in the previous code snippet, the result gets quite ugly: 

So even if you want to replace only tiny part of the view, the limitedness of granularity provided by SharePoint may force you to end up with big amounts of code. Usually I have to copy-paste the corresponding OOTB code from clienttemplates.debug.js, and then modify it slightly.

By the way, even although Footer was initially empty in my particular case, it is normally used for paging, so if you redefine it unthinkingly, the paging functionality will disappear from your list!

One obvious solution to such situations is to use OnPostRender event and perform customizations by manipulating the just rendered DOM elements, e.g. by using jQuery or HTML5 selectors.

Calling nested templates

Now, what happens if you want e.g. manipulate order of items, not touching the items themselves?

It turns out, that during the rendering process, CSR uses the ctx object for passing some additional information to the inner functions. Including the references to all of the nested methods! 

 

So using these references, you get ability to replace top CSR templates such as View, Body and Item without replacing the subtemplates.

Primitive example code for the View template: 

SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  Templates: {
    View: function(ctx) {
      return ctx.RenderHeader() + ctx.RenderBody() + ctx.RenderFooter();
    }
  }
});

Example: Color coding

Let's consider a more real-world example - color coding. So for example, I want to paint green all rows from a document library that have status "Approved". 

Since there's not much of a customization here - I need just to change a css property of an existing element, - best way to accomplish this would be to use OnPostRender event and manipulate DOM elements that were rendered by CSR. 

From OnPostRender, the ctx is accessible, thus it is not a problem to determine which documents were approved (given the Approved column is included into the view). The only tricky thing is to get the ID of the element that represents the row. Here I cheated a bit, by peeking into the CSR guts and finding a function, that generates row ids (but obviously, you can also figure out these IDs from the page source and generate them manually). 

Now everything is simple: we have the element IDs, and we can acquire field values from ctx (after a short investigation I found them in the ctx.ListData.Row array). 

So here's the final code: 

SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  OnPostRender: function(ctx) {
    var rows = ctx.ListData.Row;
    for (var i=0;i<rows.length;i++)
    {
      var isApproved = rows[i]["_ModerationStatus"] == "Approved";
      if (isApproved)
      {
        var rowElementId = GenerateIIDForListItem(ctx, rows[i]);
        var tr = document.getElementById(rowElementId);
        tr.style.backgroundColor = "#ada";
      }
    }
  }
});

This will work for English portal, but better make it international. For that, you need to replace "_ModerationStatus" with "_ModerationStatus." (dot at the end!), and compare with 0.

As you can see, SharePoint and magic are still in the same tight embrace Smile | :)

But it works:

Example: Item link 

By default, list item title links lead to view forms. What if we need them to point to edit forms?

This can be done easily with CSR, by redefining the LinkTitle field for the view.

SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  Templates: {
        Fields: {
           'LinkTitle': {'View':function(ctx) {
                  var url = String.format('{0}&amp;ID={1}', ctx.editFormUrl, ctx.CurrentItem.ID);
                  return String.format('<a href="{0}" onclick="EditItem2(event, \'{0}\');return false;">{1}</a>', url, ctx.CurrentItem.Title);
           }}
       }
  }
});

EditItem2 function is a global helper function that processes list item edit links in SharePoint. It is not mandatory, but I prefer use OOTB SharePoint functions wherever possible, because otherwise there is a chance to break some existing functionality.

ctx.editFormUrl is the URL of the edit form, and ctx.CurrentItem is data for the item that is being processed by the handler.

As you might have suspected, the contents of ctx aren't documented. Simplest way to assess the various fields of the ctx object is to put a breakpoint into your code and then use Watch window.

Result of performing the edit link customization of a Tasks list on my portal is shown on the following screenshot:

Here PageType=6 represents PAGE_EDITFORM mode, as you can verify yourself on MSDN. And indeed, the link now leads straight to the list item edit form.

Applying customizations

Ok, now you know how to write the code, but how to actually apply the created customizations to the lists?

Piece of cake:

  1. Switch the page into edit mode
  2. Add Script Editor webpart right below the list view web part.
  3. Put your code into the Script Editor
  4. Save the page

That's it. 

But of course, it's not the only way. In fact, you can put the code into the page by using any method you want - masterpage, page layout, script link, etc., just don't forget to wrap it into the SP.SOD.executeFunc call, to ensure that the clienttemplates.js file is loaded before your script is executed. 

SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function() {
 
  SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
    // ...
  });
 
})

Targeting the list view

If you have more than one list view on the page, or if you're deploying the script throughout your site rather than to only one page, you might want to ensure, that the customizations are applied to the correct list view.

For that, you can use three additional fields of the options object:

  1. ListTemplateType - ID of the list template.
  2. ViewStyle - ID of the view style.
  3. BaseViewID - BaseViewID of the list view.

ListTemplateType 

For example, if you want to customize the out-of-the-box Tasks lists, use this code: 

SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  Templates: {
    Footer: function(ctx) {
      return String.format("Hello world from {0}!", ctx.ListTitle);
    }
  },
  ListTemplateType: 171
});

IDs of standard list templates can be found on MSDN. Also custom list template IDs (10000 and above) can be used for lists based on such templates. 

ViewStyle

In truth, not every SharePoint developer even knows what is view style. For simple reason: until now, they weren't really useful Smile | :)

View style of a view can be found and edited on the Modify View page: 

 

Out-of-the-box view styles are dull and ugly. Nobody uses them. From developer's point of view, they're not quite appealing either: there's no supported way of changing those captions, and there is no supported way of adding your own styles. 

But at least you can now conveniently override how they look. Hopefully MS will provide a way to change the captions too, somewhere in future. 

So to override a view style, you need it's ID. It can be acquired from the page source: 

 

BaseViewID 

BaseViewID doesn't appear in UI. You can access it in SharePoint Designer, in Schema.xml or programmatically. It is an attribute of the View element. 

By the way, do you even know what BaseViewID is? I have it explained here on SharePoint SE

Thus, using ListTemplateType, ViewStyle and BaseViewID, it is possible to target your customizations with some sort of reliability. 

Briefly about JSLink 

I find it very embarrasing when some popular bloggers use CSR and JSLink interchangeably. 

Please remember, JSLink and CSR are completely different things, and they can very well live without each other. 

Above I created CSR customizations that don't use JSLink and work fine. 

JSLink is just a way to stick a javascript file to a SharePoint object. From that moment on, wherever this object appears, the script will be deployed as well. Script definitely can be non-CSR, e.g. jQuery, knockout.js, etc. 

JSLink property was added to the following SharePoint objects in SP2013: 

  • SPContentType
  • SPField
  • SPForm
  • SPView
  • XsltListViewWebPart
  • ListFormWebPart
  • ... and some others 

So indeed, it is very convenient to use JSLink in conjunction with CSR, because the CSR script gets the ability to "travel" wherever the list view is deployed. 

Another interesting detail, is that you can deploy several scripts at once using the JSLink property. Just separate them with "|". This is a very good way to include your CSR dependencies along with the main script. 

Conclusion 

CSR is the main rendering framework in SharePoint 2013 and thus an essential part of the system. Knowing how it works and how to use it definitely pays off. 

Benefits: 

  • Very easy to learn. You can start creating customizations literally in 10 minutes
  • Client side => less server load
  • CSR is javascript-based. Javascript community is huge and the number of different new JS libraries is astonishing.
  • Works with apps, including sharepoint-hosted
  • Huge improvement over the XSLT in terms of readability, performance, debugability, etc. 

Disadvantages: 

  • Scarcely documented
  • Sometimes requires magic skills Smile | :)
  • Unfortunately, still a long way from modern rendering frameworks, such as KnockoutJs, AngularJs, etc. 

Please note, in this article, I only explained CSR for list views. CSR is also used for displaying Quick Edit, search results and list forms. But each of these is a subject of a separate story.

So good luck, and don't hesitate to drop a comment below if you have any questions!

License

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

Share

About the Author

Andrei Markeev

Finland Finland
SharePoint MVP, author, opensource contributor, one of top experts on SharePoint StackExchange, speaker.
Follow on   Twitter   Google+

Comments and Discussions

 
QuestionOnPostRender Firing after every field render in NewForm Pin
Member 1115302715-Apr-15 4:20
memberMember 1115302715-Apr-15 4:20 
QuestionClient side rendering Pin
Member 114971653-Mar-15 22:17
memberMember 114971653-Mar-15 22:17 
AnswerRe: Client side rendering Pin
Andrei Markeev4-Mar-15 0:01
memberAndrei Markeev4-Mar-15 0:01 
GeneralRe: Client side rendering Pin
Member 114971654-Mar-15 0:18
memberMember 114971654-Mar-15 0:18 
GeneralRe: Client side rendering Pin
Member 114971654-Mar-15 0:57
memberMember 114971654-Mar-15 0:57 
GeneralRe: Client side rendering Pin
Andrei Markeev4-Mar-15 1:20
memberAndrei Markeev4-Mar-15 1:20 
GeneralRe: Client side rendering Pin
Member 114971654-Mar-15 1:28
memberMember 114971654-Mar-15 1:28 
GeneralRe: Client side rendering Pin
Andrei Markeev4-Mar-15 2:06
memberAndrei Markeev4-Mar-15 2:06 
GeneralRe: Client side rendering Pin
Member 114971654-Mar-15 1:46
memberMember 114971654-Mar-15 1:46 
GeneralRe: Client side rendering Pin
Andrei Markeev4-Mar-15 2:07
memberAndrei Markeev4-Mar-15 2:07 
GeneralRe: Client side rendering Pin
Member 114971654-Mar-15 2:26
memberMember 114971654-Mar-15 2:26 
GeneralRe: Client side rendering Pin
Andrei Markeev4-Mar-15 3:17
memberAndrei Markeev4-Mar-15 3:17 
GeneralRe: Client side rendering Pin
Member 114971654-Mar-15 3:20
memberMember 114971654-Mar-15 3:20 
GeneralMy vote of 5 Pin
lcgillies3-Mar-15 13:13
memberlcgillies3-Mar-15 13:13 
QuestionGreat article Pin
lcgillies3-Mar-15 13:12
memberlcgillies3-Mar-15 13:12 
AnswerRe: Great article Pin
Andrei Markeev3-Mar-15 23:55
memberAndrei Markeev3-Mar-15 23:55 
GeneralMy vote of 5 Pin
ricardp3-Mar-15 3:05
memberricardp3-Mar-15 3:05 
GeneralRe: My vote of 5 Pin
Andrei Markeev3-Mar-15 23:55
memberAndrei Markeev3-Mar-15 23:55 
GeneralMy vote of 5 Pin
Jerzy Czopek6-Jan-15 2:39
memberJerzy Czopek6-Jan-15 2:39 
GeneralRe: My vote of 5 Pin
Andrei Markeev3-Feb-15 11:50
memberAndrei Markeev3-Feb-15 11:50 
QuestionColor formatting disappear on Column Sort Pin
stevehn10-Dec-14 6:17
memberstevehn10-Dec-14 6:17 
AnswerRe: Color formatting disappear on Column Sort Pin
Andrei Markeev11-Dec-14 3:00
memberAndrei Markeev11-Dec-14 3:00 
GeneralRe: Color formatting disappear on Column Sort Pin
stevehn11-Dec-14 5:10
memberstevehn11-Dec-14 5:10 
QuestionRow Coloring with a Managed Metadata Field Pin
mayrmichael24-Sep-14 0:23
membermayrmichael24-Sep-14 0:23 
AnswerRe: Row Coloring with a Managed Metadata Field Pin
Andrei Markeev24-Sep-14 11:37
memberAndrei Markeev24-Sep-14 11:37 
QuestionCSR with third party search indexers Pin
Sherif Zakaria11-Sep-14 1:28
memberSherif Zakaria11-Sep-14 1:28 
AnswerRe: CSR with third party search indexers Pin
Andrei Markeev11-Sep-14 9:24
memberAndrei Markeev11-Sep-14 9:24 
GeneralRe: CSR with third party search indexers Pin
Sherif Zakaria11-Sep-14 11:12
memberSherif Zakaria11-Sep-14 11:12 
QuestionAny thoughts on handling asynchronous ClientContext calls within CSR Pin
Hj Sievert9-Sep-14 9:04
memberHj Sievert9-Sep-14 9:04 
AnswerRe: Any thoughts on handling asynchronous ClientContext calls within CSR Pin
Andrei Markeev9-Sep-14 23:06
memberAndrei Markeev9-Sep-14 23:06 
GeneralRe: Any thoughts on handling asynchronous ClientContext calls within CSR Pin
Hj Sievert11-Sep-14 5:48
memberHj Sievert11-Sep-14 5:48 
GeneralRe: Any thoughts on handling asynchronous ClientContext calls within CSR [modified] Pin
Andrei Markeev11-Sep-14 9:06
memberAndrei Markeev11-Sep-14 9:06 
GeneralMy vote of 5 Pin
Hj Sievert9-Sep-14 8:56
memberHj Sievert9-Sep-14 8:56 
Questionembed CSR in master page file Pin
Sherif Zakaria9-Sep-14 4:47
memberSherif Zakaria9-Sep-14 4:47 
AnswerRe: embed CSR in master page file Pin
Andrei Markeev9-Sep-14 23:14
memberAndrei Markeev9-Sep-14 23:14 
GeneralRe: embed CSR in master page file Pin
Sherif Zakaria10-Sep-14 11:21
memberSherif Zakaria10-Sep-14 11:21 
GeneralRe: embed CSR in master page file Pin
Andrei Markeev10-Sep-14 23:59
memberAndrei Markeev10-Sep-14 23:59 
QuestionHow to add modification for specific List View on the page? Pin
Member 105470363-Sep-14 9:32
memberMember 105470363-Sep-14 9:32 
AnswerRe: How to add modification for specific List View on the page? Pin
Andrei Markeev5-Sep-14 8:39
memberAndrei Markeev5-Sep-14 8:39 
AnswerRe: How to add modification for specific List View on the page? Pin
Andrei Markeev20-Sep-14 9:00
memberAndrei Markeev20-Sep-14 9:00 
GeneralMy vote of 5 Pin
losvce25-Aug-14 6:27
memberlosvce25-Aug-14 6:27 
GeneralRe: My vote of 5 Pin
Andrei Markeev25-Aug-14 7:12
memberAndrei Markeev25-Aug-14 7:12 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150520.1 | Last Updated 25 Aug 2014
Article Copyright 2014 by Andrei Markeev
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid