Implement Dynamic Progress Bar In List View For SharePoint 2016 And Office 365 Using Client Side Rendering

Client side rendering is a powerful option to modify the list views and the list forms. It simply means that the data is transformed and displayed, using Client side technologies like HTML and JavaScript. Prior to SharePoint 2013, in case of any requirements to modify the list views, we had to use SharePoint Designer and XSLT formatting. However, with SharePoint 2013, client side rendering has been made available. It comes in two flavors, namely:

  • Display Templates - Used to modify the search results.
  • JSLink - Used to modify the list views and list forms like NewForm.aspx

Essentially, JSLink taps into the list view rendering and overrides properties that govern the list view look and feel. Some properties that can be over ridden are:

  • OnPreRender
  • OnPostRender
  • View
  • Body
  • Item
  • Fields
  • Header
  • Footer

Let’s see how to implement a dynamic progress bar in a list column.

Requirement

Assign a percentage indicator to a blank column by calculating the percentage from the two other different columns. The percentage indicator should be color coded.



The main purpose of the client side rendering is to tap in to the rendering process. The entry point is the function, given below:

  1. SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCurrentContext);  
You can see the parameter that is passed is the client context. Before calling the override function, we have to instantiate the client context and set the property to override. In order to assign the values to each row in the list we will be overriding the fields property.
  1. (function,()  
  2. {  
  3.     varoverrideCurrentContext = {};  
  4.     overrideCurrentContext.Templates = {};  
  5.     overrideCurrentContext.Templates.Fields = {  
  6.         'Target_x0020__x0025__x0020_Reach':  
  7.         {  
  8.             'View': TargetPercentage  
  9.         }  
  10.     };  
  11.     SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCurrentContext);  
  12. })();  
Thus, we have assigned the fields property with an override. Here, we assigned a method, which will be called for each of the rows within the list. The return value will be an HTML div element, that has a percentage indicator, which is set by assigning the background color of the div element, based on the percentage value.

Now, let’s have a look at the overriding functionTargetPercentage.
  1. function TargetPercentage(ctx)  
  2. {  
  3.     vartotalSalesVal = ctx.CurrentItem.Total_x0020_Sales.replace(",""");  
  4.     vartargetSalesVal = ctx.CurrentItem.Sales_x0020_Target.replace(",""");  
  5.     varsalesPercentage =  
  6.         Math.floor((parseInt(totalSalesVal) / parseInt(targetSalesVal)) * 100);  
  7.     varpercentageIndicator;  
  8.     if (parseInt(totalSalesVal) > parseInt(targetSalesVal))  
  9.     {  
  10.         salesPercentage = 100;  
  11.         percentageIndicator = '<div style="background: #BCBCBC; display:block; height: 20px; width: 100px;"><span style="color: #fff; position:absolute; text-align: center; width: 100px;">' + salesPercentage + ' %</span><div style="background: green; height: 100%; width: ' + salesPercentage + '%"></div></div>';  
  12.     }  
  13.     else if (parseInt(salesPercentage) > 80)  
  14.     {  
  15.         percentageIndicator = '<div style="background: #BCBCBC; display:block; height: 20px; width: 100px;"><span style="color: #fff; position:absolute; text-align: center; width: 100px;">' + salesPercentage + ' %</span><div style="background: green; height: 100%; width: ' + salesPercentage + '%"></div></div>';  
  16.     }  
  17.     else if (parseInt(salesPercentage) > 50 && parseInt(salesPercentage) < 80)  
  18.     {  
  19.         percentageIndicator = '<div style="background: #BCBCBC; display:block; height: 20px; width: 100px;"><span style="color: #fff; position:absolute; text-align: center; width: 100px;">' + salesPercentage + ' %</span><div style="background: orange; height: 100%; width: ' + salesPercentage + '%"></div></div>';  
  20.     }  
  21.     else if (parseInt(salesPercentage) < 50)  
  22.     {  
  23.         percentageIndicator = '<div style="background: #BCBCBC; display:block; height: 20px; width: 100px;"><span style="color: #fff; position:absolute; text-align: center; width: 100px;">' + salesPercentage + ' %</span><div style="background: red; height: 100%; width: ' + salesPercentage + '%"></div></div>';  
  24.     }  
  25.     returnpercentageIndicator;  
  26. }  
Ctx.CurrentItem.ColumnName will get the value of the column. Since it is a number field, it has an inherent comma for the values greater than 1000. To do numerical comparison, we have to remove the comma, which is done as shown below:
  1. vartotalSalesVal =ctx.CurrentItem.Total_x0020_Sales.replace(",""");  
Once we have a comma free value, we can do the percentage calculation. Hence, let’s find the percentage of the two column values (Total sales upon Sales Target) and based on the result, we will assign the third column (Target Reached), HTML div element; which will contain a span element that mimics the percentage indicator. 
  • If the total sales are greater than the sales target, the percentage value will be set to 100 and the span will show the value as 100 and the background color of the div element will be assigned Green color.

  • If the sales percentage is greater than 80, the background color of the div element will be assigned a Green color and the span element will show the percentage value.

  • If the sales percentage is greater than 50 and less than 80, the background color of the div element will be assigned an Orange color and the span element will show the percentage value.

  • If the sales percentage is less than 50, the background color of the div element will be assigned a Red color and the span element will show the percentage value.

Since we have overridden the field property, the overriding method will run for each row in the list. Thus, the column values in each row will be compared and based on the result. The third column will have a new value. Thus, we have returned an HTML image element, that will be assigned to the destination column for each row during the rendering process.

Note

In order to implement a rendering logic to each row in the list, override the fields property.

Full Code

  1. (function()  
  2. {  
  3.     varoverrideCurrentContext = {};  
  4.     overrideCurrentContext.Templates = {};  
  5.     overrideCurrentContext.Templates.Fields = {  
  6.         'Target_x0020__x0025__x0020_Reach':  
  7.         {  
  8.             'View': TargetPercentage  
  9.         }  
  10.     };  
  11.     SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCurrentContext);  
  12. })();  
  13. function TargetPercentage(ctx)  
  14. {  
  15.     vartotalSalesVal = ctx.CurrentItem.Total_x0020_Sales.replace(",""");  
  16.     vartargetSalesVal = ctx.CurrentItem.Sales_x0020_Target.replace(",""");  
  17.     varsalesPercentage =  
  18.         Math.floor((parseInt(totalSalesVal) / parseInt(targetSalesVal)) * 100);  
  19.     varpercentageIndicator;  
  20.     if (parseInt(totalSalesVal) > parseInt(targetSalesVal))  
  21.     {  
  22.         salesPercentage = 100;  
  23.         percentageIndicator = '<div style="background: #BCBCBC; display:block; height: 20px; width: 100px;"><span style="color: #fff; position:absolute; text-align: center; width: 100px;">' + salesPercentage + ' %</span><div style="background: green; height: 100%; width: ' + salesPercentage + '%"></div></div>';  
  24.     }  
  25.     else if (parseInt(salesPercentage) > 80)  
  26.     {  
  27.         percentageIndicator = '<div style="background: #BCBCBC; display:block; height: 20px; width: 100px;"><span style="color: #fff; position:absolute; text-align: center; width: 100px;">' + salesPercentage + ' %</span><div style="background: green; height: 100%; width: ' + salesPercentage + '%"></div></div>';  
  28.     }  
  29.     else if (parseInt(salesPercentage) > 50 && parseInt(salesPercentage) < 80)  
  30.     {  
  31.         percentageIndicator = '<div style="background: #BCBCBC; display:block; height: 20px; width: 100px;"><span style="color: #fff; position:absolute; text-align: center; width: 100px;">' + salesPercentage + ' %</span><div style="background: orange; height: 100%; width: ' + salesPercentage + '%"></div></div>';  
  32.     }  
  33.     else if (parseInt(salesPercentage) < 50)  
  34.     {  
  35.         percentageIndicator = '<div style="background: #BCBCBC; display:block; height: 20px; width: 100px;"><span style="color: #fff; position:absolute; text-align: center; width: 100px;">' + salesPercentage + ' %</span><div style="background: red; height: 100%; width: ' + salesPercentage + '%"></div></div>';  
  36.     }  
  37.     returnpercentageIndicator;  
  38. }   
  • Let’s see how to add the code as JSLink to the list view. Save the code as a js file and upload it to one of the libraries say: Site Assets.

  • Go to the edit page of the list view by appending the URL “? ToolpaneView=2” at the end of the list view’s .aspxURL.

  • Click Edit Web part for the list view. Under Miscellaneous section,  there is a text box for entering JSLink.

  • Add the relative URL of the js file after ~site or ~ site collection, depending upon the location of the Site Assets library (or any other repository), where you have uploaded the js file.

Click apply. This will apply JSLink to the list view.

Output



Thus, we have seen how to implement a color coded progress bar during the run time, using client side rendering. This is quite handy , when we have to do list view formatting dynamically during the rendering time.