Applying JSLink on a Dashboard page

In this article I will discuss the issues I came across with when trying to apply jslink on a SharePoint dashboard page. For me, a dashboard page is a page on which you put multiple web parts, in order to get a global overview on a certain entity.

In order to demonstrate this, consider that you keep track of a normal task list and an issue tracking list, which you relate to the task list by means of a lookup field. I wanted to play around with the percentage complete column, so I made sure that it was added to the default view of the tasks list.
Once this was all set up, I created a new page, with a two column layout on which I add the tasks list and the issues list web parts, and connected them based on the lookup field that I created.

image

image

With the dashboard page created, I could now add some jslink to the tasks web part. I decided to simply style the Due Date and the % Complete. Here is the code I used for this:

var U2U = U2U || {};

U2U.RegisterTemplateOverrides = function () {
    // Fields template registration
    var overrideCtx = {
        Templates: {
            Fields: {
				'DueDate':
                    {
                        'View': U2U.RenderDueDate
                    },
                'PercentComplete':
                    {
                        'View': U2U.RenderPercentCompleteView
                    }
            }
        }
    };
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
};

U2U.RenderDueDate = function (ctx) {
    var value = ctx.CurrentItem[ctx.CurrentFieldSchema.Name];

    var date = new Date(value);
    var today = new Date();

    return (date < today) ? '<b>' + value + '</b>' : value;
};

U2U.RenderPercentCompleteView = function (ctx) {
    var value = ctx.CurrentItem[ctx.CurrentFieldSchema.Name];

    // .ms-TopBarBackground-bgColor
    // .ms-EmphasisBackground-bgColor

    var output = [];
    output.push('<div style="display:block; height: 20px; width: 100px;" class="ms-TopBarBackground-bgColor">');
    output.push('<span style="color: #fff; position:absolute; text-align: center; width: 100px;">');
    output.push(value);
    output.push('</span>');
    output.push('<div style="height: 100%; width: ');
    output.push(value.replace(" %", ""));
    output.push('%;" class="ms-EmphasisBackground-bgColor"></div></div>');
    return output.join('');
};

U2U.RegisterTemplateOverrides();

Notice in the code that I’m (ab)using the classes ms-TopBarBackgound-bgColor and ms-EmphasisBackground-bgColor. By using these, even when the composed look of the site would be changed, the task progress bar would still have the same look and feel as the page being hosted on.

After associating this JavaScript file with the tasks web part on my dashboard page, I noticed that the task list check boxes and the stripe through were not working any more. Moreover, the due date in the issue list was also being styled, while I didn’t associate my JavaScript file with that web part.
Now, what’s happening here?

clip_image002[4]clip_image004[4]

Fixing the original rendering of the tasklist

Now for what is happening with the task list, if you dig around in the sources of the web page (make sure the debug.js files are loaded ;-)) and compare your page without jslink to your page with jslink, you’ll find that the file hierarchytasklist.js is the one responsible for styling the task list. In the page that is using the jslink, this file is apparently loaded “long” after your file is loaded. You can find this out by putting some breakpoint in your code and in the hierarchytasklist.js.

clip_image002[6]

In order to solve this, you have to make sure the hierarchytasklist.js is registered before your code starts doing the rendering. You can achieve this by putting the next two lines before calling RegisterTemplateOverrides(ctx). I’m using the debug, because I’m not done with my issues yet …

RegisterSod('hierarchytaskslist.js', '/_layouts/15/hierarchytaskslist.debug.js');
LoadSodByKey('hierarchytaskslist.js', null);

Elio Struyf has described a solution for this in his blog post.

Now after applying this change, and having a look at the final result, the title now looks good, but I lost my rendering on the DueDate.

clip_image002[8]

Overriding the hierarchytasklist templates

To understand what is happening now, you need to understand what the file hierarchytasklist.js is doing. That file itself is actually doing the jslink registrations for a couple of fields in a task list, and thus overwriting your template for DueDate. For example, this is the template registration for DueDate:

function _registerDuedateFieldTemplate() {
ULSEhz:
    ;
    var DuedateFieldContext = {
        Templates: {
            Fields: {
                'DueDate': {
                    'View': window.DuedateFieldTemplate.RenderDuedateField
                }
            },
            ListTemplateType: 171
        }
    };

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(DuedateFieldContext);
}
ExecuteOrDelayUntilScriptLoaded(_registerDuedateFieldTemplate, 'clienttemplates.js');

You’ll notice the use of ExecuteOrDelayUntilScriptLoaded to make sure the registration does not happen until the clienttemplate.js is loaded. The clienttemplate file is the so called “engine” behind jslink doing all the necessary things on your page. Now what we want to make sure is that we register our template after hierarchytasklist has done this, and before the engine starts rendering. So let’s just use the same trick as the hierarchytasklist file is using. I pull the two lines for registration of the hierarchytasklist.js out of my RegisterTemplateOverrides and at the end of the file I add the following line:

ExecuteOrDelayUntilScriptLoaded(U2U.RegisterTemplateOverrides, 'hierarchytaskslist.js');

After applying this, problem solved! Using some breakpoints, you’ll notice that the original template is registered first but then overridden by yours.

clip_image002[10]

Back to the dashboard

Now, I didn’t look at my dashboard page for a while, assuming everything would be just fine. However, I went to the dashboard page and noticed my rendering wasn’t working at all, nor the original task hierarchy templates.

The main reason for this was that my dashboard page was running on a site with Minimal Download Strategy (MDS) enabled. So I fixed that as described here and replaced my last line, which waited on hierarchytasklist.js to be loaded, by:

//Register for MDS enabled site otherwise the display template doesn't work on refresh
U2U.sitePath = window.location.pathname.substring(0, window.location.pathname.indexOf("/_layouts/15/start.aspx"));
// CSR-override for MDS enabled site
RegisterModuleInit(U2U.sitePath + "/SiteAssets/JSLINK/tasks.js", U2U.RegisterTemplateOverrides);
//CSR-override for MDS disabled site
U2U.RegisterTemplateOverrides();

But of course, since I’m not waiting on the task hierarchy templates to be loaded any more, I lose the original styling again (i.e. check boxes, stripe-through title, …). I need to make sure that I wait for the task hierarchy templates to be loaded before clienttemplate.js can start doing the rendering.

The problem however is that you can wait for hierarchytasklist.js to be loaded, but clienttemplates.js doesn’t wait for it. If you haven’t registered your templates before he starts rendering them, then they are not applied at all. So the trick is to make sure that before he renders, everything is loaded. If you have a look at the source of your page and the file clienttemplate.debug.js, you’ll find a function RenderListView that is called from within your page, and actually starts the rendering.

clip_image002[12]

So why not make sure, that from the moment the clienttemplates.js is loaded, we alter the RenderListView function so that it waits for the necessary things to be loaded, in our case the task list hierarchy templates. So I removed the code for the MDS registration and replaced as follows, fixing the dashboard!

ExecuteOrDelayUntilScriptLoaded(
	function(){
		//Register for MDS enabled site otherwise the display template doesn't work on refresh
		U2U.sitePath = window.location.pathname.substring(0, window.location.pathname.indexOf("/_layouts/15/start.aspx"));
		// CSR-override for MDS enabled site
		RegisterModuleInit(U2U.sitePath + "/SiteAssets/JSLINK/tasks.js", U2U.RegisterTemplateOverrides);
		//CSR-override for MDS disabled site
		U2U.RegisterTemplateOverrides(); 
	},
	'hierarchytaskslist.js');

// Now override the RenderListView once the ClientTemplates.JS has been called
ExecuteOrDelayUntilScriptLoaded(
    function () {
        //Take a copy of the existing definition of RenderListView
        var originalRenderListView = RenderListView;

        //Now redefine RenderListView with our override
        RenderListView = function (ctx, webPartID) {
			ExecuteOrDelayUntilScriptLoaded(
				function(){
					// Call the original RenderListView
					originalRenderListView(ctx, webPartID);
				},
				'hierarchytaskslist.js');
        };
    }, 'clienttemplates.js');

 

clip_image002[14]

What about that DueDate column in the issues list?

We still see the DueDate column in the issues list being styled too, which is weird. That is actually because the clienttemplate.js engine applies your templates on the whole page and if your template does not limit to a certain list, view, or other, it will match any column with the same name. Now, when registering your template, you can set the property ListTemplateType to 171 to make sure it only works on task lists.
The property ListTemplateType will not help if you have multiple task list view web parts on your page that need different rendering for the same columns, have a look here on how you could possibly overcome this.

If you want to review the complete file, you can find it on GitHub.