0

I put custom stuff like textboxes and labels onto my list view via <JSLink> tag in Schema.xml. Additionally, I colorize list items <tr> background based on a field value. It all has to be done client side.

Anyway, it all works flawlessly with one exception: if I limit the items my list view displays, the textboxes I added to the view still exist, however, the list items themselves don't have background color anymore. If I remove this paging and only get one continuous list view, it works.

This is how it looks like if I initially load the page:

enter image description here

And this is how it looks like once I change the page:

enter image description here

Notice how the background isn't yellow anymore even though all 4 list items satisfy criteria for highlighting them.

I already tried attaching a change() even receiver to the <td> that contains the page numbers, but it won't fire.

Anybody know how to refresh my JS when the page is changed?

 SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function () {
            SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
                OnPostRender: function (ctx) {                  
                    currentContext = new SP.ClientContext.get_current();
                    activitiesList = currentContext.get_web().get_lists().getByTitle('Activities');
                    var query = new SP.CamlQuery();

                    #create query

                    listItems = activitiesList.getItems(query);
                    currentContext.load(listItems);
                    currentContext.executeQueryAsync(onGetItems, onFail);
                }
            });
        });

var currentContext;
var activitiesList;
var listItems;
var properties;
var contentBox;
var color;

function handlePageLegend() {

}

function onGetItems() {
    var count = listItems.get_count();

    if (count > 0) {
        getProperties();
    }
}

function onFail() {
    console.log("Legend handler failed to initialize.");
}

function addPageLegend() {
    contentBox = document.getElementById('DeltaPlaceHolderMain');
    var span = document.createElement('span');
    var input = document.createElement('input');
    var container = document.createElement('div');
    input.type = "text";
    input.id = "colorLegend";
    input.disabled = true;
    input.style["width"] = '10px';
    input.style["backgroundColor"] = color;
    container.style["text-align"] = 'right';
    container.appendChild(input);
    var desc;
    if (SP.Res.lcid == 1031)
        desc = document.createTextNode('Farbe der Konflikttermine - ');
    else
        desc = document.createTextNode('Color of conflicting appointments - ');
    container.insertBefore(desc, container.childNodes[0]);
    contentBox.insertBefore(container, contentBox.childNodes[1]);
}

function onGetProperties() {
    try {
        color = properties.get_item('legendcolor');
    }
    catch (err) {
        if (SP.Res.lcid == 1031)
            console.log('Die Listeneigenschaft "legendcolor" wurde nicht in den Listeneigenschaften gefunden.');
        else
            console.log('Property "legendcolor" was not found in list properties.');
        return;
    }
    if (color != undefined) {
        if($('#colorLegend').length == 0)
            addPageLegend();

        var rows = ctx.ListData.Row;
        for (var i = 0; i < rows.length; i++) {
            var rowId = GenerateIIDForListItem(ctx, rows[i]);
            var row = document.getElementById(rowId);
            row.style.backgroundColor = color;
        }
    }
}



function getProperties() {
    properties = activitiesList.get_rootFolder().get_properties();
    currentContext.load(properties);
    currentContext.executeQueryAsync(onGetProperties, onFail);
}

Also tried what is described here

7
  • Is Minimal Download Strategy (MDS) enabled on the site? Jul 20, 2015 at 15:56
  • It was enabled but even after disabling it in site features, the problem persists. Jul 20, 2015 at 15:58
  • Can you add your code(block) that takes care of highlighting. I presume its in OnPostRender; add code there to check you get the proper DOM references to the TR, log them to the Dev Console. Jul 20, 2015 at 17:21
  • ok I added my JS code. I add my even handler in the addPageLegend() function. Jul 20, 2015 at 19:31
  • Is there a reason you are not using the Client Side Rendering / View Override framework in order to achieve this? By using CSR, you could have code run per list item, as it is being rendered, that checks to see if the item meets the conditions for your highlighting, and apply it to that item. This should, in theory, work with paging, as the code would run as each item is being rendered, and that includes re-rendering the next batch (page) of items. Jul 20, 2015 at 19:53

2 Answers 2

1

As noted in your comment above, yes, I am referring to what you linked to in this MSDN article.

Another resource I have found to be quite useful is this article on CodePlex.

Plus there's plenty more you can find by searching for "sharepoint client side rendering".

To answer your question from the comments - no, it should not interfere with the users' ability to add or remove columns, unless they remove one of the columns that you need to use to evaluate your conditional formatting. For instance, if you have a column called "Due Date", and you base your highlighting on the value of that column, if it's removed, your code will break and the formatting will not be applied. This will definitely happen if the column is removed completely from the list, but it will also happen if the column is merely removed from the view. Any columns you need to use in your evaluation must be included in the view in order for the data to reach the client side.

Now, your comment is a bit confusing because your original question makes it seem like you want to highlight whole rows, but your comment makes it seem like you want to highlight individual columns?

Unfortunately I don't have the time right now to dig deeply enough into this to give you a definite example in code, but here is some pseudo-code that will hopefully point you in the right direction:

// this is done in order to not clutter the global namespace
var myNamespace = myNamespace || {};

myNamespace.myListOverride = {
    itemOverride: function (ctx) {
        // do whatever logic you need to do here
        // to evaluate whether or not the current item (row)
        // needs to be highlighted.  if yes, do what is necessary
        // to apply the highlighting (i.e. add a class to the
        // appropriate <tr> or <div> or whatever)
        //
        // in here you will have access to the item's data through:
        // var fieldValue = ctx.CurentItem.FieldName
    },
    fieldXOverride: function (ctx) {
        // if you want to only highlight
        // specific columns, and not an entire row,
        // you can do that in here
    },
    postRender: function (ctx) {
        // as Danny Engleman mentioned in the comments
        // you can also access DOM elements in the OnPostRender
        // event, and apply styles etc., however you lose the access
        // each item's data through ctx.CurrentItem.  you would
        // have to do extra work to find field values by extracting them
        // from the DOM elements.
    },
    render: function () {
        var overrideCtx = {};
        overrideCtx.Templates = {};
        overrideCtx.Templates.Item = myNamespace.myListOverride.itemOverride;
        overrideCtx.Templates.Fields = {
            "My Custom Field X": {
                View: myNamespace.myListOverride.fieldXOverride
            }
        };
        overrideCtx.OnPostRender = myNamespace.myListOverride.postRender;
        SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
    }
};

// this last bit will allow the rendering to happen correctly
// on MDS enabled *or* disabled sites.
RegisterModuleInit(SPClientTemplates.Utility.ReplaceUrlTokens("~site/SiteAssets/Scripts/myScript.js"), myNamespace.myListOverride.render);
myNamespace.myListOverride.render();

I highly recommend setting up something simple, setting a breakpoint in either an item override or field override, and exploring what is available on the ctx object.

3
  • thanks, I got it to work. I have updated my JS code above to demonstrate how I handled CSR while doing asynchronous callbacks. but honestly I have no idea if I did it the recommended way, just glad that it's doing it's job now. Jul 21, 2015 at 21:28
  • Great, glad it's working! I can't see your update right now, so I can't comment directly to that, but here's how I would handle that situation: first, I would try to avoid it :) If possible I would try to restructure things so no asynchronous callbacks were necessary. But, if I had to, I would probably use the item override to "tag" the items that need to be colored (with a fake css class), then fire the async call from post-render, then in the success callback, find the elements I tagged and apply the background color. Jul 21, 2015 at 21:34
  • sorry for the delay, it's updated now. Jul 21, 2015 at 22:21
0

FYI

You can also use JavaScript in Calculated Columns to color a Row; then you can use all Columns usable in a Formula to built logic.

=[Priority]
    &IF([Task Status]="Not Started" , "" ,
      "<img src=""/_layouts/images/blank.gif"" onload=""{"
        &"var row=this;while(row.tagName!='TR'){row=row.parentNode}"
        &"row.style.backgroundColor='#"
        &CHOOSE( RIGHT( LEFT( [Priority] , 2) , 1) , "fab" , "fda" , "9fa" )
      &"'}"">" 
    )

Colors the Table row based on the Priority value, but not for Not Started Tasks.. something you can not easily do with CSR because you can't access [Task Status] if it is not included in the View/ctx object.
It also works anywhere you display this Formula (in a View!! it does not work on Forms) no need for JSlink connections all over the place.

All pros and cons at http://www.viewmaster365.com/#/How

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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