1

In a document library's /Forms/AllItems.aspx, I am trying to render a column from ID to a file URL (FileLeafRef).

However this line of code:

  clientContext = new SP.ClientContext.get_current();

is giving the error:

Uncaught TypeError: Cannot read property 'get_current' of undefined

I followed this reference in stackexchange to amend my code. The error no longer show up by rending is not triggered. In below code, CSR_Setup is triggered. However overrideNameFieldTemplate and getFileLeafRefbyID is not triggered at all. The Allitems.aspx shows up without error and no change.

What's wrong?

(function () {

ExecuteOrDelayUntilScriptLoaded(CSR_Setup, "SP.js");
function CSR_Setup(){ 
    var overrideNameField = {}; 
    overrideNameField.Templates = {}; 
    overrideNameField.Templates.Fields = {
        "InstructionLibID": { "View": overrideNameFieldTemplate } 
    }; 
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideNameField); 
}

function overrideNameFieldTemplate(ctx) { 
    var InstructionLibID = ctx.CurrentItem.InstructionLibID;
    var fileRef = getFileLeafRefbyID("Instruction",InstructionLibID);
    if (InstructionLibID) {
        return "<a href='"+ fileRef + "'>Download</a>"; 
    }
    else {
        return "N/A"; 
    }
}

function getFileLeafRefbyID(LibName,Id){        
        clientContext = new SP.ClientContext.get_current();
      oWebsite = clientContext.get_web();
      oList = oWebsite.get_lists().getByTitle(LibName);

        this.oListItem = oList.getItemById(Id);
        clientContext.load(this.oListItem);
        clientContext.executeQueryAsync(
        Function.createDelegate(this, successHandler),
        Function.createDelegate(this, errorHandler)
    );

        function successHandler() {
            return(oListItem.get_item('FileLeafRef'));
        }

        function errorHandler() {
            console.log('Fail');
        }
}
})();
Mark L
  • 4,065
  • 7
  • 66
  • 128
  • Are you sure InstructionLibID is the internal name of your lookup column? – Submits May 27 '16 at 10:33
  • Yes. If I remove the line calling "getFileLeafRefbyID". The InstructionLibID column will be rendered correctly. – Mark L May 27 '16 at 10:45
  • Yes. If I remove the line calling "getFileLeafRefbyID" and call Setup_CSR without ExecuteOrDelayUntilScriptLoaded, the InstructionLibID column will be rendered correctly. Hence I am thinking ExecuteOrDelayUntilScriptLoaded actually delay my code to AFTER everything render complete? – Mark L May 27 '16 at 10:52
  • You have a ton on undeclared variables in getFileLeafRefByID and also you do not have to do new on SP.ClientContext.get_current();. But none of those things should throw "Uncaught TypeError: Cannot read property 'get_current' of undefined" – Robert Lindgren May 27 '16 at 10:53
  • Which variables have problem? Because it doesn't return any error so I may not aware. – Mark L May 27 '16 at 10:59
  • If I run CSR_Setup directly instead of ExecuteOrDelayUntilScriptLoaded(CSR_Setup, "SP.js"); I will get the Uncaught type error. If I call ExecuteOrDelayUntilScriptLoaded(CSR_Setup, "SP.js") it will call CSR_Setup without render anything and no error. – Mark L May 27 '16 at 11:00
  • That's probably because the view is done with the rendering when your query is done. You'll have to populate the values in another way, like give the tags an unique ID you pass to your success method, and set the value there – Anders Aune May 27 '16 at 11:16

3 Answers3

2

If you really want to use ClientContext with CSR Templating, you have do delay Form-Rendering until everything is loaded. You can achieve this by overloading some objects in ClientFormManager:

(function () {

    interceptForm();

    //... continue with "normal" CSR templating...


})();

function interceptForm()
{
    var CSIntercept = SPClientForms.ClientFormManager.GetClientForm;

    SPClientForms.ClientFormManager.GetClientForm = function (frmName) {
        frm = CSIntercept(frmName);
        frm.RenderClientFormCS = frm.RenderClientForm;
        frm.RenderClientForm = function () {
            ExecuteOrDelayUntilScriptLoaded(function () {
                frm.RenderClientFormCS();
            }, 'sp.js');
        }
        return frm;
    };
}
user1704029
  • 331
  • 2
  • 4
  • Wow, this seems like an excellent solution, nicely done. Aside from the obvious time that any async calls made using the client context would add, does just waiting for sp.js to load add any noticeable delay in the page loading and rendering? – Dylan Cristy Oct 20 '16 at 14:16
1

Encapsulate the content of getFileLeafRefId function in

 SP.SOD.executeFunc("sp.js", "SP.ClientContext", function () {YOUR CODE HERE }

I usually wait for "clienttemplates.js" to load for executing my jslink overrides like:

SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function () { OVERRIDE CODE HERE } 

UPDATE: Please see below your code changed with the changes I suggested (haven't tested it my self). Give it a try.

(function () {
SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function () {

    var overrideNameField = {}; 
    overrideNameField.Templates = {}; 
    overrideNameField.Templates.Fields = {
        "InstructionLibID": { "View": overrideNameFieldTemplate } 
    }; 
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideNameField); 


    function overrideNameFieldTemplate(ctx) { 
        var InstructionLibID = ctx.CurrentItem.InstructionLibID;
        var fileRef = getFileLeafRefbyID("Instruction",InstructionLibID);
        if (InstructionLibID) {
            return "<a href='"+ fileRef + "'>Download</a>"; 
        }
        else {
            return "N/A"; 
        }
    }

    function getFileLeafRefbyID(LibName,Id){     
        SP.SOD.executeFunc("sp.js", "SP.ClientContext", function () {   
            var clientContext = new SP.ClientContext.get_current();
            var oWebsite = clientContext.get_web();
            var oList = oWebsite.get_lists().getByTitle(LibName);

            this.oListItem = oList.getItemById(Id);
            clientContext.load(this.oListItem);
            clientContext.executeQueryAsync(
                Function.createDelegate(this, successHandler),
                Function.createDelegate(this, errorHandler));

            function successHandler() {
                return(oListItem.get_item('FileLeafRef'));
            }

            function errorHandler() {
                console.log('Fail');
            }
        });
    }
}); 
})();
Suleyman
  • 708
  • 5
  • 11
0

Replace

ExecuteOrDelayUntilScriptLoaded(CSR_Setup, "SP.js");

with

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

Submits
  • 3,264
  • 3
  • 22
  • 37
  • In my test, both statement exactly return same result, CSR_Setup is triggered but no Template Overrides occur. – Mark L May 27 '16 at 10:57