1

I am using JSlink file and using two functions (OnPreRender, Item).

I want to customize Item rendering but before that I want to get data from another list using OnPreRender. The issue I am facing that Item function executes before OnPreRender. Please help how can stop execution of Item until OnPreRender finishes. The below is the code.

(function () {
    function OnPreRenderDocItemTemplate(renderCtx) {
        SP.SOD.executeOrDelayUntilScriptLoaded(loadContext, 'sp.js');
        function loadContext() {
            var context = SP.ClientContext.get_current();
            var web = context.get_web();
            currentUser = web.get_currentUser();
            context.load(currentUser);
            context.executeQueryAsync(onSuccessMethod, onRequestFail);
        }
    }

    function onSuccessMethod(sender, args) {
        var account = currentUser.get_loginName();
        var currentUserAccount = account.substring(account.indexOf("|") + 1);
        alert(currentUserAccount);

        //Also needs to write logic to get data from another list
    }
    // This function runs if the executeQueryAsync call fails.
    function onRequestFail(sender, args) {
        alert('request failed' + args.get_message() + '\n' + args.get_stackTrace());
    }



    function OnPreRenderItem(renderCtx) {

        // My Login not yet
        alert("test");

        return RenderItemTemplate(renderCtx);
    }


    function RegisterDocViewTemplate() {

        var viewContext = {};
        viewContext.Templates = {};
        viewContext.Templates.OnPreRender = OnPreRenderDocItemTemplate;
        viewContext.Templates.Item = OnPreRenderItem;

            SPClientTemplates.TemplateManager.RegisterTemplateOverrides(viewContext);
    }
    ExecuteOrDelayUntilScriptLoaded(RegisterDocViewTemplate, 'clienttemplates.js');

})();

2 Answers 2

0

There area a couple things here that are probably causing the delay. First is executeOrDelayUntilScriptLoaded, obviously is making that code wait longer to execute, and I'm pretty sure that's a non-blocking process, so the rendering will just continue. Secondly, once that does eventually start to execute, what it does is fire off an asynchronous call, so that definitiely is going to add more delay and let the rendering process continue.

I don't think you can make the rendering process wait for an async call, and even if you could, you probably wouldn't want to because it will make it seem to the user that the page is taking a very long time to load.

If you need to make an async call to retrieve data from another list, consider using the Item rendering (or even a specific Field) to add some custom markup that you can easily find later, and fire off the async call after the rendering is done, then deal with the new data whenever it arrives. See my answer to this other question for an example.

4
  • Thanks for your reply. I am using Item rendering but before Item rendering I need to get the current Logged UserID and data available from another list so that I could apply my logic on Item rendering. Is it not possible in JSLink, please assist.
    – Asif
    Commented Sep 29, 2016 at 14:03
  • My point is - why do you absolutely need it before? Is it impossible to set yourself up in a way that lets you insert the additional data after the rendering, so that the multiple async calls do not interfere with the SharePoint rendering process? Commented Sep 29, 2016 at 15:19
  • Thanks. Actually, first I want to get the current loggedIn user so that I could filter list items based on that. Secondly, there are users who will be able to see items based on their role, for instance IT manager can see all items assigned to IT people etc. A unit head can see items created by him and his team. So thats why I need to get all that information before list rendering. Anyhow, if there is not any workfow in JSLink then I think I should go with Content Editor web Part using JQuery DataTable. Please advise
    – Asif
    Commented Sep 29, 2016 at 15:46
  • That might be a good way for you to go, then, yes, so you can get the data you need in the order you need it. Commented Sep 29, 2016 at 19:26
0

The JSOM code you have shared is running asynchronously, hence the execution continues even though the values have not been fetched and your success function has not been called yet.

jQuery provides deferred objects, also referred to as Promises to hold execution until an asynchronous operation is running or in other words converts your code into synchronous code.

You can refer this to learn how to create a synchronous version of executeQueryAsync method using promises.

Coming specifically to your problem, you can change your code like this:

(function () {
var account;
var account2;
var currentUserAccount;
var currentUserAccount2;
function OnPreRenderDocItemTemplate(renderCtx) {
    SP.SOD.executeOrDelayUntilScriptLoaded(loadContext, 'sp.js');
    function loadContext() {

        SP.ClientContext.prototype.executeQuery = function() {
            var deferred = $.Deferred();
            this.executeQueryAsync(
                function(){ deferred.resolve(arguments); },
                function(){ deferred.reject(arguments); }
            );
            return deferred.promise();
        };
        var context = SP.ClientContext.get_current();
        var web = context.get_web();
        currentUser = web.get_currentUser();
        context.load(currentUser);
        context.executeQuery().then(function (sender, args) {
            account = currentUser.get_loginName();
            //  currentUserAccount = account.substring(account.indexOf("|") + 1);
            //  alert(account);
            //}), (function (sender, args) {
            //    alert('request failed' + args.get_message() + '\n' + args.get_stackTrace());
        }).then(function () {
            debugger;
            var context = SP.ClientContext.get_current();
            var web = context.get_web();
            currentUser = web.get_currentUser();
            context.load(currentUser);
            return context.executeQuery();
        }).then(function (sender, args) {
            account2 = currentUser.get_loginName();
            //  currentUserAccount = account.substring(account.indexOf("|") + 1);
            alert(account2);
        });
    }
}


function OnPreRenderItem(renderCtx) {

    return RenderItemTemplate(renderCtx);

}


function RegisterDocViewTemplate() {

    var viewContext = {};
    viewContext.Templates = {};
    viewContext.Templates.OnPreRender = OnPreRenderDocItemTemplate;
    viewContext.Templates.Item = OnPreRenderItem;

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(viewContext);
}
ExecuteOrDelayUntilScriptLoaded(RegisterDocViewTemplate, 'clienttemplates.js');

})();
3
  • SP.ClientContext.prototype.executeQuery = function() { on the above line error is coming, please tell how to avoid it, i have already added Jquery reference. The error is below. Uncaught TypeError: Cannot read property 'prototype' of undefined
    – Asif
    Commented Sep 29, 2016 at 13:29
  • Have updated the code to resolve the error you've mentioned.
    – AmitWiki
    Commented Sep 29, 2016 at 16:53
  • Thanks a lot. The code is working, there were few syntax errors which I corrected. Now main point is to hold the rendering of the list OnPreRenderItem(renderCtx) until all call backs executions are complete and then use the output of the call backs in list rendering function. This was the agenda of the discussion. please tell is it possible to hold it. Thanks.
    – Asif
    Commented Sep 30, 2016 at 19:36

Your Answer

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

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