2

so I am currently using JSLink to change the look and feel of my List view, but am getting a little stuck in getting the HTML hierachy of my elements right.

This is my current code...

function ItemOverride(ctx) {
var listhtml = '<div class="listItemWrapper"><div class="vacancyListItemJobTitle">' + ctx.CurrentItem.Title + '</div></div>';
return listhtml;
}

function CustomGroup(ctx, group, groupId, listItem, listSchema, level, expand) {
var html = '<div class="vacancyRegionListHeader">' + listItem["VacancyRegion"][0].lookupValue.toUpperCase() + '</div>';
return html;
}

(function () {
var overrideCtx = {};
overrideCtx.Templates = {}; 
overrideCtx.Templates.Header = "<div id=\"vacancyList\">";
overrideCtx.Templates.Group = CustomGroup;
overrideCtx.Templates.Item = ItemOverride;
overrideCtx.Templates.Footer = "</div>";
overrideCtx.BaseViewID = 1;
overrideCtx.ListTemplateType = 100;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
})();`

What this is giving me is something like..

<div class="vacancyRegionListHeader"></div>
<div class="listItemWrapper"></div>
<div class="vacancyRegionListHeader"></div>
<div class="listItemWrapper"></div>
<div class="listItemWrapper"></div>
<div class="vacancyRegionListHeader"></div>
<div class="listItemWrapper"></div>

but what Im looking for is something like the following output

<div class="vacancyRegionListHeader">
    <div class="itemGroupWrapper">
        <div class="listItemWrapper"></div>
    </div>
</div>
<div class="vacancyRegionListHeader">
    <div class="itemGroupWrapper">
        <div class="listItemWrapper"></div>
        <div class="listItemWrapper"></div>
    </div>
</div>
<div class="vacancyRegionListHeader">
    <div class="itemGroupWrapper">        
        <div class="listItemWrapper"></div>
    </div>
</div>

As you can tell, I want all the items to be contained in a div container, under each group header container. Reason for this is because I am wanting to have a javascript function that, when a .vacancyRegionListHeader is clicked, it collapses the whole next div item (which would be all the list items).

Currently my current implementation only collapses the first item under the header, and not all the items in the group.

How can I get the result using my JSLink functions?

From what i can tell, the code is first seeing the group then creates the header html. Then sees each item, and creates the HTML. Then sees another group, and creates the header HTML, etc. I don't know how to generate the ItemOverride function within a group override. Or at least create some sort of group 'groupHeader'-listItems-'groupFooter' type thing.

any ideas?

Thanks!

  • Where are the itemGroupWrapper divs coming from? I don't see them in your code. Is that the SP default group rendering? Are you just wanting to wrap the SP default group rendering with another div? – Dylan Cristy May 26 '15 at 16:17
  • Hey Dylan, the itemGroupWrapper div is not in my code yet, but a div I want to somehow put in, just not sure how. So Im wanting to wrap all listItems into the groupWrapper, under a ListHeader – Simon May 26 '15 at 16:24
2

Ok, this answer is going to be a bit long, because I haven't worked with overriding the group rendering template, so I'm basing my answer on my experience overriding the view rendering template.

First of all, you should know that you can call the default SP rendering methods from within your custom override. So for instance, you could conceivably do something like this (again, this is just speculation based on what I have done with overriding a view):

function CustomGroup(ctx) {
    // also note that i am not referencing a specific listitem, as you did,
    // which i'mn guessing was to add the group name to the header.
    // not sure how you can work that one out.

    // add the opening tags of what we want to wrap the group in
    var html = '<div class="vacancyRegionListHeader">' + somehowGetYourGroupName;
    html += '<div class="itemGroupWrapper">';

    // let SharePoint render the content of the group as it would normally,
    // which should take into account your item override
    html += ctx.RenderGroups(ctx);

    // close our wrapper tags
    html += '</div></div>';
    return html;
}

You may need to throw in a breakpoint and step through the process to understand what's really happening when SP renders groups. I say this because when working with overriding views, I discovered that the view rendering actually gets called twice - the first pass renders the header and body, the second pass renders the footer. This was important for me to know because I wanted to add to the header and the footer. Here's my code for my view override (which works as intended):

function CustomView (ctx) {
    // view gets called twice during the rendering process
    var viewHtml = "";

    // first pass, Header will be a function and Footer will be an empty string
    if (typeof ctx.Templates.Header == "function") {
        viewHtml += "add my custom html that I want in the header";
    }

    // the built in functions internally handle not double rendering,
    // so just let them do their thing
    viewHtml += ctx.RenderHeader(ctx);
    viewHtml += ctx.RenderBody(ctx);
    viewHtml += ctx.RenderFooter(ctx);

    // second pass, Header will be an empty string and Footer will be a function
    if (typeof ctx.Templates.Footer == "function") {
        viewHtml += "add my custom HTML that I want in the footer";
    }
    return viewHtml;
}

Here's a link to a great article that breaks down List View rendering overrides.

In that article, he talks about being able to call the default rendering methods, but says something along the lines of

function CustomView (ctx) {
    return ctx.RenderHeader() + ctx.RenderBody() + ctx.RenderFooter();
}

but I have found that you have to pass the ctx as an argument to the rendering methods, or nothing will render.

Hope you can use some of the ideas here to get where you want to go!

2

Thanks Dylan, for your great detailed answer. While I was thinking about implementing it, another developer and I quickly brainstormed a different solution which works as well for us, and a little less 'complicated'.. :) (in the sense that its not much different to the way I had it working before and how I understood it..)

So basically, Im adding the itemGroupWrapper opening div to my groupHeader HTML, and use a variable to check if its the first groupHeader (where we don't include the end div), else if not we close the end div.

Then in the final footer for the template, we close the last itemGroupHeader div.

Your suggestion Im sure makes more sense from a more control point of view, but this was a satisfactory way for us to wrap the items in wrapper within the group sections. :)

var firstItemPassed = false;

function ItemOverrideFun(ctx) {
    var listhtml = '<div class="listItemWrapper"></div>';
    return listhtml;
} 

function CustomGroup(ctx, group, groupId, listItem, listSchema, level, expand) {
    var html = ""
    if(!firstItemPassed){
        firstItemPassed = true;
        html = '<div class="vacancyRegionListHeader">' + listItem["VacancyRegion"][0].lookupValue.toUpperCase() + ')</div><div class="itemGroupWrapper">';
    }
    else{
        html = '</div><div class="vacancyRegionListHeader">' + listItem["VacancyRegion"][0].lookupValue.toUpperCase() + ')</div><div class="itemGroupWrapper">';
    }
    return html;
}

// anonymous self-executing function to setup JSLink templates on page load..
(function () {
var overrideCtx = {};
overrideCtx.Templates = {};

overrideCtx.Templates.Header = "<div id=\"vacancyList\">";
overrideCtx.Templates.Group = CustomGroup;
overrideCtx.Templates.Item = ItemOverrideFun;
overrideCtx.Templates.Footer = "</div></div>";

overrideCtx.BaseViewID = 1;
overrideCtx.ListTemplateType = 100;

SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
})();
  • Hello @SimonZA , could you please provide the html obtained from that solution please ? I am in the same issue as you and can't make it work (plus i'm using lists) Thansk ! – Gaelle Oct 25 '16 at 9:28
2

I used Dylan's answer to help me come up with a solution to override the promoted links no item text.

SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  BaseViewID : 1,
  ListTemplateType : 170,
  Templates : {
    View : function(ctx) {
      if(ctx.ListData.Row.length == 0 && typeof ctx.Templates.Body == 'function') {
        ctx.Templates.Body = function(ctx) {
          return 'No promoted links!';
        };
      }
      return RenderViewTemplate(ctx);
    }
  }
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.