4

I've read several walkthroughs on client-side rendering (CSR) and JSlink, and the methods to target only one list on a page instead of all lists.

I understand that I can target using two things: ListTemplateType : 100 and BaseViewID.

However, I don't understand why I am unable to target using other things, like listName or view.

Is there a way to find out other methods that I can use to target a specific list?

For example, I am currently able to target like this:

SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
ListTemplateType  : 100,
BaseViewID = 1,
Footer: ...

But I wonder if there are any ways other than ListTemplateType and BaseViewID to target

2 Answers2

5

I don't understand why I am unable to target using other things, like listName or view.

The short answer is: because that's how Microsoft designed it, and that's all they gave us. It definitely is kind of a bummer.

Keep in mind that ListTemplateType: 100 is only referring to custom lists. If you have views to other OOB SharePoint list types (Contacts, Document Library, etc.) on the same page, you would be using a different ListTemplateType value.

That being said, yes, you are still using ListTemplateType as the differentiator to keep the CSR scripts from stomping on each other.

I assume you have read about the workaround for the problem of having multiple list views all pointing at custom lists on the same page, where they all end up with ListTemplateType: 100 and BaseViewID: 1.

Now, off the top of my head (and this is completely untested by me, maybe someone else has tried this) another way you might be able to target different lists with different CSR scripts is by using content types. The SPContentType object has a JSLink property. If you create custom content types instead of just adding columns directly to lists, and then attach the different CSR scripts to the content types, and then go and add the content types to different custom (but essentially empty) lists, that might be a way to associate a particular script with a particular list.

I have no idea what would really happen in practice though if you then created a page with multiple List View Web Parts on it, each pointing to one of the different lists. But, theoretically (from what I understand), the different scripts should get pulled in because they are following the content types.

Whether or not SharePoint would then intelligently use the content types as a differentiator for selectively applying the rendering is another question.

Another way you could possibly do it, which is kind of messy but I think could work (although I don't think I'll ever try this), is to put some conditional checks into your CSR code. Something like this (pure pseudo-code):

if (ctx.CurrentListName == "my targeted list") {

    return MyCustomRendering();

} else {

    return SharePointDefaultRendering();
}

It is possible to access the default SharePoint rendering methods from inside the CSR overrides, but that's just... bleah.


To try and briefly explain how the workaround (linked to above) works, here's what's happening:

First, you add your list view web parts to the page you want them on. Then you look at the page in developer tools, and look at it in "source" mode so you are looking at the script on the page. Find the section on the bottom where SP is passing all the information about the lists. There you can see which WPQ# ID SP has assigned for each of your list views.

Armed with that knowledge, you set the BaseViewID properties in your CSR scripts to something deliberate and high, like 99, 98, etc., so you can force a match later. Say you saw that List A was assigned WPQ2. You set your override code to have BaseViewID: 99.

Then, you add another script which hijacks the default call to RenderListView. When your hijacked function gets called, you check which WPQ# the rendering call is for, quickly sneak in the BaseViewID you previously set up for your own override code, and then re-call the real RenderListView. So in the example case:

if (ctx.wpq == 'WPQ2') // we know that SP assigned List A to have WPQ2
{
    ctx.BaseViewID = 99; // force the BaseViewID to be what we set in our List A override code
}

Then SP goes "hmmm, do I have any registered overrides for BaseViewID: 99? Why yes I do." And then executes your rendering override code.

It is a very fragile workaround, because it's all based on you gaining knowledge of which WPQ# ID SP has assigned to your web parts, and if you add or remove a web part from the page, SP will re-assign those IDs, and you'll have to go back in and re-code your forced matching. (For instance, if you add or remove a web part, the List A view might no longer be assigned WPQ2, and now your substitution won't match up to the right override code anymore.)

Dylan Cristy
  • 12,712
  • 3
  • 31
  • 71
  • Can't he also create a list definition in an add-in based on an existing list and use that ID to target the list? Won't it be the same as targeting the list? As mentioned here: https://msdn.microsoft.com/en-us/library/office/jj220045.aspx – Akhoy Oct 02 '15 at 04:26
  • @Akhoy although the article you link to implies that you can define views with different BaseViewIDs and use custom list definition's ListTemplateType ID, the way the rendering system targets that particular list and view to apply the overrides is still through the mechanism of ListTemplateType and BaseViewID, and I think the OP's question is about how to not use those properties to target a list. – Dylan Cristy Oct 02 '15 at 14:22
  • Thanks for clarifying. OP wanted to target a custom list. So creating a custom list definition would make sure that that list is targeted, right? Just saying. Would appreciate if you could clarify :) Need more info on this. – Akhoy Oct 02 '15 at 16:16
  • @DylanCristy Thanks a lot! I honestly don't understand the methods in the article you linked to for the workaround. I'm trying to figure it out. As Akhoy mentions, I am in fact just looking for a way to target one list in particular - I don't care how I do it, I just don't want my rendering to affect other lists on the page. And also, what is wrong with your if/else statement? It's just untidy? – Matthew J Mammola Oct 02 '15 at 17:43
  • @MatthewJMammola, updated my answer with an (attempt at an) explanation. – Dylan Cristy Oct 02 '15 at 18:23
  • @Akhoy, honestly I'm not sure. I created a list instance and definition, and specified a template type of 70000 in the CAML. But when I checked the default LVWP page (AllItems.aspx) for the list after it got deployed, it still showed ListViewTemplateType: 100. The article implied that the template type would be the number you specified in the definition, but that's not the behavior I saw. Also, I did not try defining any other views with different BaseViewIDs, so I don't know if that would come through correctly or not. Could be worth some testing. – Dylan Cristy Oct 02 '15 at 18:30
  • @DylanCristy Thanks so much! That helps to understand the flow. If we're matching our list by using WPQ#, can't we also check our list based on listTitle (as the article author initially wrote) or listName or view or any of the other unique identifies of a list? – Matthew J Mammola Oct 02 '15 at 18:52
  • @MatthewJMammola, yes, I suppose you could, as long as it shows up on the ctx object that is being passed to the rendering function. But keep in mind that you are doing that in in a separate script so that you can deliberately manipulate the BaseViewID, and that your main CSR override code still has to use ListTemplateType and BaseViewID as the identifiers. – Dylan Cristy Oct 02 '15 at 18:56
0

I had a similar problem, but could not use the solution above because I had the same list on the page in more than one list view.

My CSR was applied in the JSLink property and I happened to be doing all my processing in the OnPostRender function.

So, for me this worked:- OnPostRender: function (ctx) {
// JSLink applies to ALL "custom" lists on a page // Examine the ctx and see if THIS file is requested in THIS call if (ctx.ListSchema.JSLink.length === 0) return // No JS Link so exit var isLinked = false ctx.ListSchema.JSLink.forEach(function (v, i, r) { if (v.indexOf('transposelistview.js')) isLinked = true }) if (!isLinked) return ...