Sunday 20 January 2013

Using JSLink to change the UI of a SharePoint list/view

Changing the user interface of certain bits of SharePoint has always been somewhat challenging – at least, if we want to avoid the SharePoint Designer route and produce something which is packaged, deployable as a WSP and repeatable across many sites. Not to mention source-controlled. A common area of customization is the user interface around SharePoint lists - when it comes to this, there are a few “flavours” of common requests:

  • Custom list forms – e.g. a more “designed” form for adding and/or editing items
  • Custom behaviour for a certain field - e.g. a “UK address” field which allows postcode lookup
  • Custom rendering of a list in display mode (e.g. the ‘All items’ view) – a good example of this is conditional formatting e.g. “Add a red background to the row if the value for ‘Days overdue’ is over 5”

As you might guess from the article title, it’s the third scenario that this article focuses on, for SharePoint 2013 specifically.

Earlier versions of SharePoint gave us a couple of approaches for fulfilling some of these requirements. We could create a custom field control (item number 2 above) or modify the XSLT of an XsltListView perhaps (number 3 above) – a method that was new in SP2010 of course, since we previously had CAML rendering for list views (yuck). SharePoint 2013 brings a new JavaScript-based approach for modifying the UI of fields and lists, and many more things too. You’ll often see this referred to as “JSLink”, because many things in SP2013 have a new JSLink property which you use to point to your JavaScript file. Here’s a list of SharePoint objects which you can modify in this way:

SharePointTypesWithJSLinkProperty

Lots of interesting possibilities there – all the field types are obviously represented, but binding UI changes to a:

  • content type
  • form
  • view
  • list view web part instance (rather than to the list/view itself)

..could all be extremely useful.

[As an aside, if you came to this article looking for a solution to the 1st scenario above (modifying forms), you’ll probably be interested that SPForm has a JSLink property. However I imagine there’s still a place for providing entirely custom forms as opposed to making relatively small changes with JavaScript. The old approaches still apply here - modifying list forms is easy in SPD, but requires a bit more thought in the Visual Studio world. In that case, we’d probably want to NOT edit the original .aspx, but instead provide a different .aspx file and update the SPList.NewFormUrl and/or SPList.EditFormUrl properties to point to it (e.g. in a Feature receiver).]

Implementing changes to list rendering with JSLink

For a recent SharePoint talk, I wanted a fairly dramatic example of changing the UI of a list (when looking at list items). So, my example showed changing the list from this:

JSLink_NoCustomTemplate

..to this:

JSLink_AccordionList1

There are some slightly nasty scrollbars in these images, but that’s just because I’ve reduced the size of the window for my screenshots - normally the accordion looks great. As you might imagine, I get a nice sliding “expand and contract” experience when I select different items:

JSLink_AccordionList2

If you’ve worked with it before, you’ll immediately recognise this as the accordion from jQuery UI. In many ways, it’s a nice example, since although YOU are unlikely to need/want to use jQuery accordion for your “customizing a list” needs, it uses custom CSS, images and JavaScript to provide rendering which you probably ARE going to need. So, I’ll walk through most aspects of this process, but as you’ll see only around 20% of the work relates to the JSLink stuff – the rest is just scaffolding. We’ll cover the JSLink specifics first.

The full Visual Studio project can be downloaded at the end of this article.

The important bit (part 1)– how to hook up your custom rendering with JSLink (e.g. call into jQuery UI accordion)

The first thing to say is that when we want to change the rendering of a SharePoint list, it’s actually individual views (SPView) we’ll be working with. The SPList class does NOT have a JSLink property, which makes sense given this is all about presentation. Getting SharePoint to “see” your custom rendering will probably depend on what you’re doing:

Scenario

Approach

Creating a new list Specify the path to your .js file in the schema.xml file for the list (specifically within the declaration for the view)
Modifying an existing list In code, update the SPLink property (i.e. SPView.JSLink) to provide the path to your .js file (using PowerShell/server-side/client-side API as appropriate)

This bit only ensures your .js file is referenced by the page. You also need to make sure it has the right contents to register your display templates – we’ll come to that in a second.

In my case, I’m creating a new list – it’s worth noting that I’m assigning a list type ID of “11000” – we’ll use this later with respect to JSLink:

CreateListForAccordion3

When developing for SharePoint 2013 onwards, when a list is created in Visual Studio the JSLink element for any views will contain “clienttemplates.js”:

NewCustomList_DefaultJSLink

..but we should change that to our custom JavaScript file which has our display template implementation (you’ll see me deploy this later):

NewCustomList_CustomJSLink

Our file will then be loaded when this view is requested (i.e. SharePoint will add the .js file to the page). But that’s not enough – we now have to think about what JavaScript is needed to actually register the templates. This is done by specifying two properties of the list views to match:

  • OPTIONAL - the BaseViewID property (e.g. BaseViewID=1 for a standard view like “All items”, but you could use another ID for a custom view)
  • The ListTemplateType property (for a new list, you’ll be specifying a unique integer value e.g. 10000)

So, it’s usually a combination of THREE controls overall which dictate how rendering is applied to a list view – the JSLink path, BaseViewID and ListTemplateType. Although BaseViewID appears to be optional, it seems sensible to set it to avoid unforeseen problems with Explorer View/Datasheet View etc. So for a given list, if you wanted one view to have custom rendering and one to have default rendering (even though they share a BaseViewID), simply ensure the JSLink property for the default one is NOT set to your custom .js file.

I also note that it appears possible to specify multiple values in a JSLink path – I haven’t tried this, but I see things like <JSLink>mquery.js|contentfollowing.js</JSLink> (note the pipe character) within out-of-the-box files under the 15 folder.

The important bit (part 2)– what your JavaScript should look like:

Here’s my full AccordionListView.js file specified in the JSLink property for my view – I supply a header and footer and then a JavaScript method (function pointer) to execute for each list item. Notice some context gets passed to this function, including details of the list item:

As you might be able to infer, the jQuery UI accordion expects a H3 and div element for each item – so that’s what my template does, in addition to actually calling the accordion() method.

An issue with JSLink and the Minimal Download Strategy (MDS)?

Continuing my recent tradition of discovering slightly strange behaviour around what I’m writing about, this week is no exception. In my testing, I noticed that if a list has multiple views and the user switches between them, the client templates specified by JSLink do not get applied if MDS is enabled (even though the debugger shows they are called). I’m hoping that I’m doing something wrong, but I can’t rule out a bug in SharePoint 2013’s MDS framework at this stage.

If anyone sees this/has any info, please leave a comment :)

Integrating CSS/JS (such as jQuery UI) into the solution

OK, so if all you wanted to know about was the JSLink aspect, we’re now done covering that. Hopefully that was useful. The remaining bits of this article will cover the “scaffolding” aspects of my particular jQuery UI accordion example – integrating jQuery/jQuery UI, and so on.

My first step was to go to the jQuery UI Download Builder and download the files (plus jQuery too if you don’t have it already). If you haven’t done this before, you can basically configure some options (e.g. styles, behaviors, jQuery UI widgets to use) to build a package for download – this means you get a smaller package than if you were opted for all styles and all jQuery UI components. You’ll therefore have lower page weight and better performance, than if you were using the full set. However, I had an issue where my solution would only work with the full jQuery UI file rather than the one I “built” – if this was production code I’d stop and resolve this, but for demoware I was OK with it.

When you get your download and crack it open, you’ll have some CSS and JavaScript files:

jQueryUIFiles

jQueryUICSSFiles

jQueryUIJSFiles

I chose a grey-ish theme called “overcast”, and within the CSS folder come a stack of images – we’ll need to integrate all of these files into our VS project:

jQueryUIThemeImages

In my project, I created a “Site Assets” folder to house my supporting images, CSS and JavaScript – since I’m working in a sandboxed solution, I need these to go into the content database and in my case the contents get deployed to the SharePoint library of the same name. After copy/pasting these files into my Visual Studio project, I get this:

jQueryUI_FilesInSolution

..and, 0f course, Visual Studio is kind enough to detect the new files and generates my elements.xml file accordingly:

The next step is to ensure the site we’re deploying to references these files – we’ll deal with JavaScript first and then CSS.

Add jQuery/jQuery UI to the page (in this case, every page in the web)

Here we need to ensure jQuery and jQuery UI are added to pages in the site. Since we’re not deploying a custom master page (and don’t want to use the Content Editor web part to add JS to the page), we’ll need to use either CustomAction + ScriptLink or a delegate control going into ‘AdditionalPageHead’. In my case I’m choosing the former so that my solution works in the cloud (as a sandboxed solution):

Notice that I’m referencing a non-minified version of jQuery UI – that was the issue I said earlier that I would resolve for production use. The next step is CSS.

Ensure the jQuery UI branding/CSS is applied

Since we’re not using a custom master page, we’re just using the AlternateCssUrl property of the web to ensure our custom CSS file is referenced by our pages:

Our site should now receive all branding and JavaScript dependencies – so if we were to deploy a static page with the correct HTML for a jQuery UI accordion, then it should work fine. However, we want ours to serve as the UI for a SharePoint list, so we’ll now create that list. In the final step we’ll do the actual JSLink work – this will change the rendering of the list at run-time.

Create the list we will use with JSLink

Nothing special here and I won’t go into every step – but it is worth mentioning that creating a list via Visual Studio 2012 is much easier than before:

CreateListForAccordion

..then add whatever columns your list needs (here I’m adding them direct to the list rather than to a content type):

CreateListForAccordion2

As we mentioned earlier, we are allocating a new list type ID  (the value used was 11000) for the underlying template for this list – this is important since, in this “new list” scenario, we’re using a combination of this and the BaseViewID for the "All items” view to hang our JSLink customizations off:

CreateListForAccordion3

Finally I add some dummy data (some old blog articles) to my list so each time I deploy/test, I don’t have to manually add list items:

Download link

You can download my Visual Studio project for this sample here.

Conclusion

SharePoint 2013 brings some great possibilities for customizing the user interface, and JSLink/client-side rendering is central to much of this. The great news is that it’s all cloud-friendly, so these techniques can be used in Office 365. The solution above was implemented as a sandboxed solution, and the only code was really to set the AlternateCssUrl of the site. As a result, it would be fairly easy to move all this to a SharePoint app if needed.

Hopefully this has been useful in understanding how JSLink/client rendering might be a valuable tool.

27 comments:

thomyg said...

Hi!

Great blog post Chris!

I have a short question about the webpart property JSLink that every webpart in 2013 has:

https://dl.dropbox.com/u/4867945/js_link-webpart-property.png

Is this heading in the same direction? Can we just apply our custom CSR JS as an hyperlink to an already existing list?

thx!!!

Chris O'Brien said...

@thomyg,

Yes, that gives you a way to target individual web part instances (e.g. a list view web part). As opposed to the custom rendering being attached to the view itself.

HTH,

Chris.

Anonymous said...

Hi Chris,

I've created a similar example, however deploying the actual list, instance and resources (jquery libs and CSS) in a SharePoint-hosted app, which actually get load via Custom Actions. This should solve the need to change the AlternateCSS and no Sandbox solution needed either. Actually, no compiled code is deployed.

Chris O'Brien said...

@Nettitude,

Nice. I'm guessing your stuff is all happening in the app web - in my case, I wanted the list to reside in a team site which is why I chose the sandbox route. I'm sure the implementations are very similar though.

Good stuff!

C.

Anonymous said...

Yes Chris, you are absolutely right. In my case, I wanted a "one-piece" solution - so that if needed could be published to the store and run standalone.

Regards,
C:\>Marius

Lam Le said...

Hi Chris,

Just a confirmation that if MDS is activated on the site, the JavaScript does not work when I tried to switch to different List views. I tried to delete cache in IE but it doesn't help. This also true for any Javascript one would use in CEWP. I have not tried it with the new SP App yet.

Hope this is a bug and not a "work as design", as it would make MDS almost unusable in many installations.

Thanks for the article.

Anatoly Mironov said...

Hi Chris!

This is really good stuff. Thanks for the pedagogical explanation!

You use a customizable list. I have a standard non-customizable list: Announcements. Is it possible to add a JSLink to my list?

Anatoly

Chris O'Brien said...

@Lam,

OK, sounds like I'm not the only one seeing this - appreciate the confirmation. I'm going to close my eyes for a bit and hope my inbox brings news of an update very soon ;)

I'll update the article if I hear anything, but would also love to hear from anyone else who discovers something here.

Thanks,

Chris.

Chris O'Brien said...

@Miron,

Absolutely - you would just need to set the SPList.JSLink property to point to your JS file (and register the templates in your JS). Check out the 'Modifying an existing list' item in the Scenarios table above.

Good luck!

Chris.

Anonymous said...

Hi @Chris,
I copied your solution and deployed the solution on my new SharePoint 2013 site. I am getting this error : window.COB is undefined
Source File: http://siteURL/siteassets/accordionlistview.js?ctag=1$$15.0.4420.1017
Line: 7
Please help me in this! Thanks in Advace.

Anonymous said...

Hi Chris,
once again a great post from your side with the complete code help. I deployed the code provided by you in your post, not working in IE8 :( can you help, also h2-tag and b-tag not working for me.
Please help.
Thanks for your help.

Chris O'Brien said...

@Anonymous (both),

Oops - sorry, you're right! There was originally an error in the JavaScript which got uploaded - this has now been fixed in the code sample within the article. I'll update the full project download tonight.

Apologies for the inconvenience!

Thanks,

Chris.

Chris O'Brien said...

All,

Just to confirm the main download link was updated with the fix.

Thanks,

Chris.

Wes Preston said...

And while this covers the developer side of things, you can also implement changes using the JS Link web part property without using Visual Studio.

http://www.idubbs.com/blog/2012/js-link-for-sharepoint-2013-web-partsa-quick-functional-primer/

Wes Preston

Amit said...

Thanks for the nice article !!

Our requirement for a SharePoint 2013 app is to render the UI of the list view as a Kendo UI grid, such that users can perform filtering, sorting, grouping and other features provided by kendo grid at the UI itself. The columns will be added by users in the list view at runtime and the same needs to appear automatically in the Kendo UI grid too.

Using JSLink property, I am able to change the appearance of how a particular field renders inside list view. Is it possible to change the appearance of complete list view to render as Kendo UI grid, using the JSLink property. Looking for ideas on how to achieve the same.

Nigel said...

Hi Chris I knew I could rely on your blog to dig me out of a hole. Great Blog ! I have managed to get this to work on O365 public web site by manually deploying everything to that same place as you did with VS2012. The only issue I had was in the AccordianListView.js last function ($(document).ready(function () )threw a '$' is undefined error so I put into the Pagelayout in the PlaceHolderAdditionalPageHead content placeholder after the script inclusions for the JQuery files. It all then burst into life.

Regards

Nigel

Anonymous said...

I am noticing the same thing that you are experiencing with the MDS. If I turn the feature off it works fine, with it on it intermittently doesn't work, mostly when going from one view to another. Any new information on configurations for this?

Paul Hunt said...

Just to add a little note, I hit the MDS issue too, then found this nugget on the Developers blog for SharePoint. It describes how to register your script for MDS enabled or disabled sites.

http://blogs.technet.com/b/sharepointdevelopersupport/archive/2013/02/08/register-csr-override-on-mds-enabled-sharepoint-2013-site.aspx

Chris O'Brien said...

@Paul,

Ah excellent, thanks. I'd been meaning to spend time digging into the MDS issue.

Cheers!

Chris.

Paul Hunt said...

Hi Chris,

I blogged a while back on an issue when registering Display Templates using JSLink when there is more than 1 list view web part sourced from the same ListTemplateID and Base view ID resulting in all list views receiving the rendering.

I found a client side resolution for that and have blogged on it.
It's on my blog here.

BRM013 said...

Chris,
I was wondering if you have had any luck embedding web parts in page layouts and using the jslink property?

I've got a web part which works when its added and configured (with jslink) to a web part zone but I'm trying to embed it in a page layout using the Design Manager feature. The web part renders in the pages that use the page layout but the jslink file is not getting loaded/processed.

Cheers,
Brett

Akki said...

Chris, it is a great post. Have you tried to update a ContentType JSlink property programmatically.

Chris O'Brien said...

@aruna g,

No, afraid I haven't tried SPContentType.JSLink. Good luck :)

Chris.

aackose said...

Hi Chris,

Great Post and happy to see MS moving more towards Client Side Rendering & scripting.

I was trying to add multiple List View Webparts in the same page pointing to different lists. ex. A Menu List, an Accordion List & a Link list. And use different Js files for JsLink to render them differently. ex. Accordion list will render the list with accordion functionality, menu list will render the list items to construct a Mega Menu etc.

When i load each of the List View independently, Js link works fine. However, when i load them all at once in the page, the first list view appear to work fine but the next two behaves similar. ex. I ended up having Link List working fine, but the menu list and Accordion list behaving like an accordion.

Somehow, i could see that as the BaseViewID changes, it was working fine.

Have you faced any such issue with multiple List View on the same page using different JsLink files?

Chris O'Brien said...

@aackose,

It's a good question - the only approach I really know about is to add some conditional logic to your display template JavaScript. You could either "mess with" the BaseViewID, or perhaps look for the list title in your JS method - both techniques are written about by Paul Hunt at ListView Web Part issues with JSLink and Display Templates – A solution?.

HTH,

Chris.

aackose said...

Thanks Chris,
I checked with Paul on this and tried his solution. Worked out just fine.

Ova (Excuse My Reading) said...

Thank you Chris. Always better than Microsoft Documentation :)