My last post was about client side rendering customization. I wrote how to change the UI of a listview based on some values of the SharePoint list item. I realized that changes i made in my JSLink file are displayed but sometimes they are only available after a hard refresh (STRG+F5). When i first navigate to the list it looks like this:
After hitting STRG+ F5 it looks like i was expecting it to look:
What is the reason and what can i do?
Ok first the reason ist MDS – Minimal Download Strategy. There is a really cool post which explains it pretty good. And of course i got it working thanks to this great post of Wictor Wilén.
What can i do?
I just changed my code a little bit. The important steps are the following:
- Create a Namespace like ILS
- Define the Functions and Templates inside the namespace
- Implement a register function for MDS and non-MDS Sites
The background is explained in the posts i linked in my post, but to cut a long story short, the namespace has to be registered correctly to work in MDS, cause MDS just reloads the Delta and contains something like a garbage collector, which removes global variables. So we register our Namespace everytime and make sure that it will load our customization with each page load.
My example can be downloaded here.
[sourcecode language=”csharp”]
Type.registerNamespace(‘ILS’)
ILS.Demos = ILS.Demos || {};
ILS.Demos.Templates = ILS.Demos.Templates || {};
ILS.Demos.Functions = ILS.Demos.Functions || {};
ILS.Demos.Functions.CreateDateFormat = function(ctx)
{
//Convert the CreateDate into a number with getTime()
//ATTENTION: We Split by using ‘/’ if you turn to another language setting it might not working!
var CreateDate = new Date(ctx.CurrentItem.CreateDate.split(‘/’)[2],ctx.CurrentItem.CreateDate.split(‘/’)[0]-1,ctx.CurrentItem.CreateDate.split(‘/’)[1]).getTime();
var today = new Date();
today.setHours(0,0,0,0);
var todayNo = today.getTime();
//Compare and react
if(CreateDate == ‘undefined’ || !CreateDate)
{
return ctx.CurrentItem.CreateDate;
}
else if(CreateDate < todayNo)
{
return "“+ctx.CurrentItem.CreateDate+”“;
}
else if(CreateDate == todayNo)
{
return ““+ctx.CurrentItem.CreateDate+”“;
}
else
{
return ctx.CurrentItem.CreateDate;
}
}
ILS.Demos.Functions.PriorityFormat = function(ctx)
{
var priorityValue = ctx.CurrentItem.Priority;
if(priorityValue == ‘High’)
{
return ““+ctx.CurrentItem.Priority+”“;
}
else
{
return ctx.CurrentItem.Priority;
}
}
ILS.Demos.Functions.PercentCompleteFormat = function(ctx)
{
var returnvalue = ‘
‘;
return returnvalue;
}
ILS.Demos.Functions.HighlightRowOverride = function(ctx)
{
for(var i=0; i < ctx.ListData.Row.length; i++)
{
var listItem = ctx.ListData.Row[i];
var iid = GenerateIIDForListItem(ctx, listItem);
var row = document.getElementById(iid);
if(listItem.Marked == "Yes")
{
row.style.backgroundColor = "rgba(4,92,8,0.1)";
}
}
ctx.skipNextAnimation = true;
}
ILS.Demos.OnPostRender = [ILS.Demos.Functions.HighlightRowOverride];
ILS.Demos.Templates.Fields = {
"Priority": {"View": ILS.Demos.Functions.PriorityFormat },
"PercentComplete": {"View": ILS.Demos.Functions.PercentCompleteFormat },
"CreateDate": {"View": ILS.Demos.Functions.CreateDateFormat }
};
ILS.Demos.Functions.RegisterField = function () {
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(ILS.Demos)
}
ILS.Demos.Functions.MdsRegisterField = function () {
var thisUrl = _spPageContextInfo.siteServerRelativeUrl
+ "/_catalogs/masterpage/Display Templates/cond_formatting.js";
ILS.Demos.Functions.RegisterField();
//That's an important step when MDS is active
RegisterModuleInit(thisUrl, ILS.Demos.Functions.RegisterField)
};
//Starting
//If _spPageContextInfo is available the MDS is activated, we have to register our function
if (typeof _spPageContextInfo != "undefined" &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; _spPageContextInfo != null) {
ILS.Demos.Functions.MdsRegisterField();
}
else
{
//MDS is not activated, we register our Functions
ILS.Demos.Functions.RegisterField();
}
[/sourcecode]
That's it. I know it is not well documented on the web, but for me the post of Wictor helped a lot and just trying.
If you have more ideas or improvements please let me know.
Hi Karsten, I have tried using your tips to implement the conditional formating but after spending several hours, I am unable to make it work. It would be nice if I can share it with you via Lynx or anything else to get it working. Appreciate any help you can provide for your time and effort.
Regards,
Vijay
Karsten, your code works beautifully for me. There is one item that has eluded me. When I filter a list and manually refresh I get the following error: TypeError: Cannot read property ‘style’ of null.
I am guessing that this is caused by the filter process throwing the row id off. I have not been able to figure out how to resolve this issue. Would you be able to provide me with guidance?
Thank you very much for your helpful code and assistance.
Hi Karsten,
I tried both your codes for applying Conditional formatting to my list in Sharepoint 2013 but none of them worked properly.
Below is the Code – Could you please let me know what wrong am I doing which is restricting the conditional formatting to apply
(function () {
var condFieldCtx = {};
// Define template variable
condFieldCtx.Templates = {};
// Define your required fields and functions to call in each case.
// In our case the field is Progress
// Override Function is PatientProgressViewTemplate
condFieldCtx.Templates.Fields = {
“Impact”: {“View”: ImpactFormat},
“Likelihood”: {“View”: LikelihoodFormat},
“Severity”: {“View”: SeverityFormat}
“Level of Control”: (“View”: LevelofControlFormat)
};
//conditional formatting for a complete row comes here
condFieldCtx.OnPostRender = [HighlightRowOverride];
// Register the template override with SP2013
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(condFieldCtx);
})();
function ImpactFormat(ctx)
{
var impactValue = ctx.CurrentItem.Impact;
if(impactValue == ‘1. Negligible’)
{
return “”+ctx.CurrentItem.Impact+””;
}
else
if(impactValue == ‘2. Minor’)
{
return “”+ctx.CurrentItem.Impact+””;
}
else
if(impactValue == ‘3. Moderate’)
{
return “”+ctx.CurrentItem.Impact+””;
}
else
if(impactValue == ‘4. Major’)
{
return “”+ctx.CurrentItem.Impact+””;
}
else
if(impactValue == ‘5. Critical’)
{
return “”+ctx.CurrentItem.Impact+””;
}
else
{
return ctx.CurrentItem.Impact;
}
}
function LikelihoodFormat(ctx)
{
var likelihoodValue = ctx.CurrentItem.Likelihood;
if(likelihoodValue == ‘1. Rare’)
{
return “”+ctx.CurrentItem.Likelihood+””;
}
else
if(likelihoodValue == ‘2. Unlikely’)
{
return “”+ctx.CurrentItem.Likelihood+””;
}
else
if(likelihoodValue == ‘3. Possible’)
{
return “”+ctx.CurrentItem.Likelihood+””;
}
else
if(likelihoodValue == ‘4. Highly Likely’)
{
return “”+ctx.CurrentItem.Likelihood+””;
}
else
if(likelihoodValue == ‘5. Almost Certain’)
{
return “”+ctx.CurrentItem.Likelihood+””;
}
else
{
return ctx.CurrentItem.Likelihood;
}
}
function SeverityFormat(ctx)
{
var severityValue = ctx.CurrentItem.Severity;
if(severityValue == ‘1. Very Low’)
{
return “”+ctx.CurrentItem.Severity+””;
}
else
if(severityValue == ‘2. Low’)
{
return “”+ctx.CurrentItem.Severity+””;
}
else
if(severityValue == ‘3. Moderate’)
{
return “”+ctx.CurrentItem.Severity+””;
}
else
if(severityValue == ‘4. High’)
{
return “”+ctx.CurrentItem.Severity+””;
}
else
if(severityValue == ‘5. Very High’)
{
return “”+ctx.CurrentItem.Severity+””;
}
else
{
return ctx.CurrentItem.Severity;
}
}
function LevelofControlFormat(ctx)
{
var levelofcontrolValue = ctx.CurrentItem.LevelofControl;
if(levelofcontrolValue == ‘1. No Controls’)
{
return “”+ctx.CurrentItem.LevelofControl+””;
}
else
if(levelofcontrolValue == ‘2. Minimal Controls’)
{
return “”+ctx.CurrentItem.LevelofControl+””;
}
else
if(levelofcontrolValue == ‘3. Some Control’)
{
return “”+ctx.CurrentItem.LevelofControl+””;
}
else
if(levelofcontrolValue == ‘4. Adequately Controlled’)
{
return “”+ctx.CurrentItem.LevelofControl+””;
}
else
if(levelofcontrolValue == ‘5. Well Controlled’)
{
return “”+ctx.CurrentItem.LevelofControl+””;
}
else
{
return ctx.CurrentItem.LevelofControl;
}
}