11

I'm trying to execute CSOM functions as part of a JSLink extension to override rendering of a Lookup Field.

Problem is every time I try to access SP.ClientContext it returns as undefined

I have tried calling an executeOrDelayUntilScriptLoaded operation to load the context, but my JSLink "rendering" functions always execute WAY before this actually does anything.

SP.SOD.executeOrDelayUntilScriptLoaded(loadContext, 'sp.js');

function loadContext() {
    context = SP.ClientContext.get_current();
    web = context.get_web();
}

If I try putting my JSLink callback functions inside this then they never actually work (and I just get OOB rendering).

hatch.testRender = function (ctx) {
    alert(context); // always returns "undefined"
}
Vardhaman Deshpande
  • 10,462
  • 1
  • 26
  • 52
Martin Hatch
  • 1,303
  • 3
  • 13
  • 26

8 Answers8

12

SharePoint 2013 CSR OnPreRender handler could used for initialization of ClientContext since OnPreRender is called before the actual View/Fields rendering

Example:

(function () {   


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


    function RegisterDocViewTemplate() {

        var viewContext = {};
        viewContext.Templates = {};
        viewContext.Templates.OnPreRender = OnPreRenderDocItemTemplate; 
        SPClientTemplates.TemplateManager.RegisterTemplateOverrides(viewContext);
    }
    ExecuteOrDelayUntilScriptLoaded(RegisterDocViewTemplate, 'clienttemplates.js');

})();
Vadim Gremyachev
  • 42,498
  • 3
  • 86
  • 167
3

I worked around this problem by having the custom render function return just a placeholder HTML element, and using a $(window).load handler to later populate the element with content obtained through JSOM calls.

By the time the handler executes, the necessary JavaScript libraries have already been loaded, and SP.ClientContext is also available.

2

I experienced the same issue using JSLink in O365 Sharepoint Online. My solution was to call my function requiring SP.ClientContext as follows:

//Perform SP.ClientContext tasks after sp.js is loaded
window.onload = function() { SP.SOD.executeFunc('sp.js','SP.ClientContext', someFunction()); };
arbiter34
  • 21
  • 1
1

Adding another answer to this question with yet another solution:

Instead of messing around with ExecuteOrDelayUntilScriptLoaded or SP.SOD.executeFunc, I simply added the JSOM files that I needed to get loaded into my JSLink.

So for instance, I needed to use the SP.WorkflowServices namespace. In order to use that, according to this MSDN page, the required files are:

  • SP.js
  • SP.Runtime.js
  • SP.WorkflowServices.js

And of course they have to be loaded in order. So my JSLink for the particular field I'm overriding looks like:

clienttemplates.js|sp.js|sp.runtime.js|sp.workflowservices.js|~site/path/to/my-csr-script.js

And whatever framework is handling loading the JSLink files respects the order, so the files get loaded correctly, and I can use SP.WorkflowServices in my CSR override code.

Dylan Cristy
  • 12,712
  • 3
  • 31
  • 71
0

The problem I have had with SP.ClientContext undefined was problem with the load library.

My solution did reference to MicrosoftAjax on cloud and not my solution.

I believe when you build a SharePoint solution, itself did it.

I solved changing the references. I downloaded library and add into the my solution, another words, there are not references out solution.

Amal Hashim
  • 28,306
  • 5
  • 31
  • 61
0

I ran into this problem also.

I suspected what was happening was that while the code is delaying for 'SP.js' to load, 'clientTemplates.js' is running full steam ahead and calls RenderListView() before the code can execute RegisterTemplateOverrides().

My answer to this was to leverage @Aveenav's answer to overriding the BaseViewId on Using Different BaseViewID values for multiple JSLink on a single page

(function(){
    //Delay the execution of RenderListView until sp.js is loaded
    ExecuteOrDelayUntilScriptLoaded(function() {
         //Take a copy of the existing Microsoft Definition of RenderListView
         var oldRenderListView = RenderListView;

         //Now delay the execution of the rest of RenderListView until sp.js is loaded
         RenderListView = function(ctx,webPartID) {
             ExecuteOrDelayUntilScriptLoaded(function() {
                 oldRenderListView(ctx,webPartID);
             }, 'sp.js');
         }
    }, 'ClientTemplates.js');
    // Continue with Template Overrides
})();

Testing this showed that I had access to SP.ClientContext within the onPostRender() function (which was where I needed it.)

BM-
  • 163
  • 1
  • 6
0

Try this:

SP.SOD.executeFunc('sp.js','SP.ClientContext',loadContext);

function loadContext() {
    context = SP.ClientContext.get_current();
    web = context.get_web();
}
Vardhaman Deshpande
  • 10,462
  • 1
  • 26
  • 52
  • As I put in my original post something like that works but if I try to include it in my JSLink render functions then my custom rendering gets ignored by SharePoint. If I put it outside of the JSLink render functions then it doesn't execute in time (so is always undefined during rendering) – Martin Hatch Aug 17 '13 at 20:52
0

I had a similar problem. It worked well when I moved all my SP.ClientContext code inside the onInit event. You need to register onInit event and call CSOM inside that event. This event executes once all controls are loaded ..

Kunal Valecha
  • 444
  • 1
  • 4
  • 12