Tuesday, October 21, 2014

JSLink and Display Templates Part 5 – Creating custom List Views

Copyright from: www.martinhatch.com

This post will look at a slightly different scenario – List Views. The general principles are the same (we write some JavaScript which tells SharePoint to override the rendering of various elements) but because we are now dealing with a whole view instead of just a single field there are some new elements to play with.
This is actually one of the more simple examples so I’ll start with all of the JavaScript in one block
var mjhViews = mjhViews || {};
mjhViews.itemHtml = function (ctx) {
  var returnHtml = 

 + ctx.CurrentItem.Title + 
;
  if (ctx.CurrentItem.MyCustomField) {
    returnHtml += “” + ctx.CurrentItem.MyCustomField + 
;
  }  
  return returnHtml;
};
(function () {
  var mjhOverrides = {};
  mjhOverrides.Templates = {};
  mjhOverrides.Templates.Header = 
;
  mjhOverrides.Templates.Item = mjhViews.itemHtml;
  mjhOverrides.Templates.Footer = 
;
  
  mjhOverrides.ListTemplateType = 104;
  mjhOverrides.BaseViewID = 1;
  
  SPClientTemplates.TemplateManager.RegisterTemplateOverrides(mjhOverrides);
})();


So we start off as good JavaScript developers and create ourselves a namespace (mjhViews) for our function (so we don’t pollute the global namespace). This contains a single function (mjhViews.itemHtml) which accepts the same render context object we’ve been using throughout this series.
The itemHtml method simply returns some basic HTML consisting of the item Title in an H2 element followed by the “MyCustomField” (if it exists, this field was used in Parts 3 and 4). Of course there are different methods for retrieving the values of the current item but the render context will automatically provide properties for the basic data types (some field types, external data fields in particular, don’t work like this and you might need to get creative with AJAX REST calls but be careful about performance!).
Finally we have our anonymous function which actually registers this override with SharePoint, and this is where things get interesting.
The main thing you might notice here is that we aren’t controlling any specific fields but instead override the “Header” and “Footer” with plain old HTML. For the “Item” we reference our rendering method and this will be executed for every item present in the view.
We then have two more properties (both of which are optional by the way).
The ListTemplateType and the BaseViewID both define which specific list types and views this rendering should be used for. If you don’t specify values for these then when this rendering override is registered it will override EVERY list and view on the page.
Finally we use the same old RegisterTemplateOverrides to tell SharePoint to process our object and do its thing!
Now before I apply this view it looks like this (which should be a pretty familiar SharePoint view):
Standard SharePoint list view
Once I apply my custom view rendering it looks like this:
A custom (if slightly boring) list view done with JavaScript
So .. quite easy huh? But the bright among you might have wondered .. where the hell has the toolbar and paging gone? Ahh .. yes .. that is all handled by the header and footer.
The header and footer contain important List View elements
This isn’t the only setback, if you try to use the view I defined above in “Quick Edit” mode then you also get the following error message:
TypeError: Unable to get property ‘style’ of undefined or null reference
The problem is that if you don’t override the Header you get some slightly funky behaviour because the headers injects a table object and it expects your content to be rendered inside that HTML table as rows. So by default I end up with the following (note the headers are at the bottom!)
Custom rendering with the header intact, but column headers are appearing AFTER the other content
So if you really want to play ball with the list views (and want the headers to be available) then you need to use TR and TD elements for your render HTML. For example:
mjhViews.itemHtml = function (ctx) {
  // start with a and a
  var returnHtml = “ ” ;
  returnHtml += 

 + ctx.CurrentItem.Title + 
;
  if (ctx.CurrentItem.MyCustomField) {
    returnHtml += “” + ctx.CurrentItem.MyCustomField + 
;
  }  // close off our and elements
  returnHtml += ;
  return returnHtml;
};
Once we put this in place, our headers are back in the right place.
Custom rendering with column headers in the right place
Making your views use the correct Display Template
In order to make sure the Display Templates are used in the correct places you have a number of options.
  1. In your schema.xml of a custom list definition you can define the JSLink property allowing you to override specific views. This allows you to build List Templates which have completely bespoke views when required (especially useful for use with list view web parts)
  2. You can define the JSLink property on the List View Web Part .. and this works either for defined views in the List or for List View Web Parts which you have dropped onto other web part pages or publishing pages.
  3. You can use Code / PowerShell to modify the JSLink property of the SPView object programmatically
  4. You can of course just drop in your JavaScript file using a Script Editor or custom Master Page and use the ListTemplateType and BaseViewID properties I told you about at the beginning on this post :)
  5. or you can use a funky new method which allows users to create their own views using your custom templates … but more about that in Part 6 :)
So that pretty much covers off how list views can be rendered using bespoke code. Hope you’ve been enjoying the series but we’re not done yet!

No comments: