Article
11 comments

Bind JSLink overrides to certain web parts only

JSLink can only be registered on certain list templates. This works well as long as only one web part on a page will be shown. If you added multiple list views of the same list template the template override will affect all web parts and not only the one that has the JSLink File attached to. To avoid this behavior the template override needs to be able somehow to conditional format the output.

Use Case for conditional web part formatting

Let’s say we have a list that shows all the incoming and outgoing money. While the outgoing money has a leading minus sign the incoming money only shows positive values. Now we like to show this list as a summary on the landing page. Additionally, we like to add a second list view on the landing page that shows only incoming money. For a better visualization, we like to show the values of the first web part in a different color. Red for negative values and green values for incoming money.
This makes sense for the first web part, but not for the second because it is filtered to show only positive values.
In Excel this is a pretty easy task to accomplish because all we need to do is to simply format the cells with the conditional formatting. In SharePoint we need to override the field rendering using JSLink.

Two web parts of the the same list showing sum field

Two web parts of the the same list showing sum field

In SharePoint the default view only shows the values in black.
The default views don’t look that nice because all the “Sum” fields on the page looks black. The only difference is the small minus sign right in front of the actual amount.
On the other hand it does not make sense to clear the list below two because only values that are greater than zero will be shown.

Apply JSLink to highlight positive and negative values

To show the values of the “Sum” field in different colors all that needs to be done is to write a field override. The following code implements such a basic field override.

(function () {

  var myFormContext = {
    Templates: {
      Fields: {
        Sum:{
          View: function(ctx){
            // Text value displayed 
            var sumText = ctx.CurrentItem.Sum;

            // Float value of field
            var sumValue = ctx.CurrentItem['Sum.'];
           
            if(sumValue < 0){
              return "<span style='color: red'>"+sumText+"</span>";
            } else {
              return "<span style='color: green'>"+sumText+"</span>";
            }
          }
        }
      }
    },
    ListTemplateType: 100
  };

  SPClientTemplates.TemplateManager.RegisterTemplateOverrides(myFormContext);

})();

You might noticed inside the “View” that I worked with two different values. The “sumValue” and the “sumText”.

ctx.CurrentItem.Sum:
This property contains the rendered field value, including the currency sign.
ctx.CurrentItem[‘Sum.’]:
The property “Sum.” needs to be requested using the array notation because the dot has a special meaning in JavaScript.
I added this JSLink override to the first web part only, but the result looks like this.

Web part with attached field override

Web part with attached field override

Not really the expected result. JSLink attached to only one web part affects all the fields that exist on a page. In this case the “Sum” field of the same generic list exists two times on the page and all the instances will be overwritten.
To avoid that the JSLink will be attached to both web parts we need to find a way how to differentiate the web parts.

Bind JSLink to certain Web Parts only

To make the UI changes only available in a single or multiple web part, but not all we need to find a way to detect which web part called the field override.
Paul Hunt posted a solution in his blog post “ListView Web Part issues with JSLink and Display Templates – A solution?“. This solution works great, but what I was looking for is a more generic approach.
One thing that has all list view web parts in common is the view. Every list view web part has its own view id. This characteristic is independent of list template type or any other property and can used in all approach.
You now might wonder if the view id won’t change, when the view of the web part changes. Actually No.
The view id always stays the same as long as the web part is added to the page. If you remove the web part and re-add it you will get a new view ID. All view changes, that will be made on an existing web part will result in the same view id. Even if you changed one of the default list views. What SharePoint actually does is to copy the view configuration to the same view id.

Get View ID from web part

To me the view ID is the only constant in the game of applying JSLink to only some web parts. It’s convenient to have a javascript object that stores all the information. The only downside of using the view id is that is not directly visible in the HTML source code.
This can be solved using a simple trick. To display additional information such as the view id the best option from my point of view is the footer that can be appended to any web part. To display the view ID we only need to add the following code inside the overwrite.

Update April 2015: The code shown below is out dated – Read the whole story on: Footer override might break the pagination if the code is used this way.

...
Templates: {
  Footer: function(ctx){
      
      // Check if display mode have already been requested
      // Otherwise request display mode
      if(!displayMode){
        // Fetch the display mode 
        displayMode = document.getElementById("MSOSPWebPartManager_DisplayModeName");
        
        // Check if displayMode has been set to Design
        // If so show debugging information 
        if(displayMode.value == "Design"){
          showFooterDebugInfo = true;
        } else {
          showFooterDebugInfo = false;
        }

      }
      // If it is not Design aka Web Part Edit view
      // Don't show View ID
      if(showFooterDebugInfo === false){
        return "";
      }
      // Show View ID in web part edit mode
      return "<strong>View ID:</strong>   "+ctx.view;

  },
  Fields: {
...

The variables “displayMode” and “showFooterDebugInfo” are defined as global variables. This avoids requesting the same value for every web part because of the page only one DisplayModeName can be assigned. You can copy the code right before the field override or download the complete code at the end of this blog post.

The result of this code, the view ID will only be displayed on the web part edit view.

Display web part with and without footer

Display web part with and without footer

The next thing that is left to do is to check the override against a specific view.

Check field override against the view

Now the last thing left to do is to add a simple “if-Statement”, inside the field override. If the current view requested from the context object matches the id of the configured view return the reformatted strings; otherwise just return the actual value.
The code needs to be extended with the following lines:

...
Fields: {
  Sum:{
    View: function(ctx){
      // Float value of field
      var sumValue = ctx.CurrentItem['Sum.'];
      
      // Text value displayed 
      var sumText = ctx.CurrentItem.Sum;
      
      // Check if current web part matches the defined view
      if(ctx.view != '{AEC4F0D8-464E-4E40-A9E0-5C898BEA6A02}'){
         return ctx.CurrentItem.Sum;
      }
      
      if(sumValue < 0){
          return "<span style='color: red'>"+sumText+"</span>";
      } else {
          return "<span style='color: green'>"+sumText+"</span>";
      }
    }
  }
}
...

The result now looks as expected. The first web part shows the highlighted “Sum”-Field according to the values.

Display final result with field override only attached to a single web part

Display final result with field override only attached to a single web part

Negative values will be rendered in red; positive values will be rendered in green. The web part below shows the values unchanged.

Summary

In this blog post I showed how different field overrides override can be applied to only certain web parts based on the same list template type. The following three things I think are important to remember:
Dealing with Number fields in JS Link

A period behind the field name shows that the field is numeric. This can be accessed using array short notation on the JavaScript Object.

Use static information to bind overrides

The view ID is such a static information that remains on the page however you configure your web part. The only thing that will lead to a new view id is to remove the web part and add a new web part.

So this was the last blog post for this year.

I wish you all a good start into the new year !!!

Further reading

List View Web Parts and JSLink Display Template rendering issues

11 Comments

  1. Hi Stefan, thanks for the call-out to my original solution. I agree it’s not an elegant fix and is definitely a work around for something that I think Microsoft missed a trick on.

    I like this method for field render overrides and it should be nicely interchangeable with View Overrides too. I’ll give it a test and get it added into my JSLink sessions at future User Groups.
    Paul.

    Reply

  2. What if you want to completely ignore a web part? If the view id does not match then nothing is returned and the header and item object displays on screen as undefined.

    Mark

    Reply

    • If I understood you correctly you want to apply a JS Link to all web parts except one web part. In this case you need to invert the if-statement and check if the view ID doesn’t match. This will ignore this specific web part.

      Reply

  3. Hi Stefan,

    I’m facing the same issue and followed the steps but it did not fix it. Below is scenario
    I created a list and added a JSLink file to it. Added the same as an Apppart on the page and it works perfectly.
    Then i created another list (not related to first list) added a seperate JSLink file to it and its working perfectly, however if i embed both of them on the same page the first jslink stops working and is overridden by the second JSLink. I tried the above approach but still the same issue
    Can you help?

    Note: I’m overriding the complete list using JSLink in both cases on just Fields.

    Regards,
    Jagjot Singh

    Reply

    • Hi Jagiot,

      have you used a different namespace for both jslink override? To avoid side effects you should name the first override formcontext1 and the second formcontext2 or something like that.

      /Stefan

      Reply

      • Hi Stefan,

        thanks for the response, i have provided different namespaces for both overrides, however the issue is once the both jslinks are loaded, i’m doing a button click on the first jslink which breaks as it tries to get data from the second jslink list. So is it possible to
        1) Reattach the context object back to the first list after another jslink is loaded on button click.
        2) load the the first jslink completely after the second jslink (execute delay). I tried this approach as i added the execute delay on the entire jslink but in did not fire my code and normal list is rendered.

        Any help is greatly appreciated.

        Thanks,
        Jagjot

        Reply

Leave a Reply

Required fields are marked *.


This site uses Akismet to reduce spam. Learn how your comment data is processed.