Quantcast
Channel: CHUVASH.eu » async
Viewing all articles
Browse latest Browse all 4

Client Side Rendering with Async dependencies

$
0
0

Yesterday I asked a question on SharePoint StackExchange:

I also asked Elio Struyf on Twitter:

Good idea, Elio Struyf! Now I want to try it out.

Preparations

In this case I’ll be using my example from my blog post yesterday:

Drag and Drop Image using Client Side Rendering

I have created a new list and added a lookup field to my previous list. What I get is a Title of the lookup item, but not my custom field called DragAndDrop. In my test I will try to load the DragAndDrop Image using an ajax call and rendering it after Client Side Rendering is done with my item.

To be complete, I want to show some screenshots for my lookup field:

csr-async-001csr-async-002

It will result in this OOTB rendering:
csr-async-003

Trying out CSR with async dependencies

While working with jslink, first of all I want to show a loading image instead of an empty html element, to show that something is loading:
csr-async-004

Here is the skeletton of the jslink file:

(function () {
    'use strict';

    var display = function (ctx, field) {
        var containerId = "tolle";
        var loadingImg = _spPageContextInfo.webAbsoluteUrl + "/_layouts/images/loadingcirclests16.gif";
        //unfortunately SP.Utilities.Utility is not defined at this stage
        //SP.Utilities.Utility.getImageUrl("loadingcirclests16.gif");       
        return ['<div id="', containerId, '"><img src="', loadingImg, '"/></div>'].join('');
    };

    var overrideContext = {};
    overrideContext.Templates = overrideContext.Templates || {};
    overrideContext.Templates = overrideContext.Templates || {};
    overrideContext.Templates.Fields = {
        'TolleLookup': {
            'DisplayForm': display
        }
    };

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideContext);
})();

Making an ajax call

Next step is to initiate an ajax call. I am trying to avoid the jQuery dependency. There is so much you can do with the built-in javascript functions. For making an ajax call I am using SP.RequestExecutor.js

Here is the result:

csr-async-005

The code should be quite self explaining:

(function () {
    'use strict';

    var onDataRetrieved = function(response) {
        console.log("yippie");
        var data = JSON.parse(response.body);
        var imgSrc = data.d.DragAndDropImage;
        var container = document.getElementById("tolle");
        container.innerHTML = ['<img src="', imgSrc, '"/>'].join('');
    }

    var onError = function(response) {
        console.error("failed", response);
    }
    var initiateAjaxCall = function(ctx) {
        var item = ctx.CurrentItem;
        var fieldName = ctx.CurrentFieldSchema.Name;
        var fieldValue = item[fieldName];
        
        var itemId = fieldValue.split(";#")[0];
        var lookupListId = ctx.ListSchema.Field[0].LookupListId;
        var url = [window._spPageContextInfo.webAbsoluteUrl,
            "/_api/web/lists/getbyid('",
            lookupListId,
            "')/Items(",
            itemId, ")?$select=DragAndDropImage"].join("");
        SP.SOD.registerSod('sp.requestexecutor.js', '/_layouts/15/sp.requestexecutor.js');
        SP.SOD.executeFunc("sp.requestexecutor.js", "SP.RequestExecutor", function () {
            var executor = new SP.RequestExecutor(window._spPageContextInfo.webAbsoluteUrl);
            executor.executeAsync(
                {
                    url: url,
                    method: "GET",
                    headers: { "Accept": "application/json; odata=verbose" },
                    success: onDataRetrieved,
                    error: onError
                }
            );
        });
    }
    var display = function (ctx, field) {
        if (!ctx.CurrentItem[ctx.CurrentFieldSchema.Name]) { //if there is no value
            return "";
        }
        var containerId = "tolle";
        var loadingImg = window._spPageContextInfo.webAbsoluteUrl + "/_layouts/images/loadingcirclests16.gif";
        initiateAjaxCall(ctx);
        //unfortunately SP.Utilities.Utility is not defined at this stage
        //SP.Utilities.Utility.getImageUrl("loadingcirclests16.gif");       
        return ['<div id="', containerId, '"><img src="', loadingImg, '"/></div>'].join('');
    };

    var overrideContext = {};
    overrideContext.Templates = overrideContext.Templates || {};
    overrideContext.Templates = overrideContext.Templates || {};
    overrideContext.Templates.Fields = {
        'TolleLookup': {
            'DisplayForm': display
        }
    };

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideContext);
})();

Next steps and further considerations

It seems to work, although I have some considerations:

  1. What happens if the data from the ajax call is retrieved before Client Side Rendering is done (then the container is not rendered yet). Even if the risk for that is low, it should be handled properly.
  2. It would be good to have a consistent look and feel in the Display form and in the list view. To make it possible, following should be done:
    1. We must create references to html elements (containers) with unique ids, need to implement logic for generating ids and keeping track of the right elements.
    2. Ajax calls should be bundled, otherwise it will hugely impact the performance, even in a list view with 30 items.


Viewing all articles
Browse latest Browse all 4

Latest Images

Trending Articles





Latest Images