5

We have two different lists that we are setting up some jslink client-side rendering files for their edit forms. Both csr files use the SP.Guid.newGuid() function to id some DOM elements in the markup. One list worked just fine, but the other list always failed because the function was undefined.

We checked in the debugger and for the one list we noticed that none of the sp files — sp, sp.runtime, sp.core, sp.init, etc — had loaded. It seems like all that stuff should be loaded by the time we are rendering the form, right?

So my first question is, "Why would those files be loaded for one list's edit form, but not for another?"

Started looking for solutions and found this thread which shows using SP.SOD.executeOrDelayUntilScriptLoaded() with the customContext.Templates.OnPreRender. That solutions was for list views and maybe it is different, but on an Edit form the OnPreRender is called for every field. It might work, but seems like not the best solution to me.

Also I might need to require several other files. So I thought I could try a using load multiple, something like this:

function initForm(){

    var ctx = {OnPreRender: myPreRender,
       Templates:{
           Fields:{
               Title:{"EditForm":fancyField}
               ...
           }
    }}

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(ctx);
}

RegisterSod('sp.js', '/_layouts/15/sp.js');
RegisterSod('sp.init.js', '/_layouts/15/sp.init.js');
RegisterSod('reputation.js', '/_layouts/15/reputation.js');

SP.SOD.loadMultiple(
    ['sp.js',
     'sp.init.js',
     'reputation.js'
    ],function(){initForm()}
)

But that didn't work because the form loaded and was all rendered before the csr code ran and registered the template overrides.

Then I found this thread which shows how you can specify multiple files to load in the jslink iteself, like so.

~sitecollection/_layouts/15/sp.init.js|~site/SiteAssets/csrListName.js

That does work, but I don't like it. It makes the csr file less portable to my mind. There is nothing self-contained in the csr file that shows the requirements for it to function and it requires going to edit the webpart and examine the jslink property to see what is required.

So my second question is this, "Is there a way to ensure the loading of required (perhaps multiple) SharePoint js files for a client-side rendering file within the file itself?"

  • can you check in chrome console Network tab if sp.js gets loaded on you both the editform? Also execute this javascript SP.Guid.newGuid() on chrome's console of both edit form pages and see if that works? – Ahmad Zia Oct 18 '17 at 4:59
  • It does load eventually, but not in time for the csr file. The solution of having to put all needed files into the JS Link isn't a very good solution, so I'm looking for some other way to be sure they load, but before the csr file. – Rothrock Oct 18 '17 at 15:00
  • Thanks @Rothrock for clarification. Please see my answer below. Just as a side note, why do you need SP.js in csr? – Ahmad Zia Oct 19 '17 at 1:22
3

I also faced the same issue sp.js and sp.runtime.js etc. were not loading with page load I tried different approaches finally with below code I am able to load them, might help

<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.core.js"></script>
<script type="text/javascript" src="/_layouts/15/1033/strings.js"></script>
<script type="text/javascript" src="/_layouts/15/clienttemplates.js"></script>
<script type="text/javascript" src="/_layouts/15/clientforms.js"></script>
<script type="text/javascript" src="/_layouts/15/clientpeoplepicker.js"></script>
<script type="text/javascript" src="/_layouts/15/autofill.js"></script>
<script type="text/javascript">
$(function() {
    getSPOffset();
    LoadData();
});

function initializePeoplePicker(peoplePickerElementId, allowMultipleValues, isPeopleOnly, GroupID, user) {
//debugger;
                        SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function() {
                            var schema = {};
                            if(isPeopleOnly) {
                                schema['PrincipalAccountType'] = 'User';
                            }
                            else {
                                schema['PrincipalAccountType'] = 'User,DL,SecGroup,SPGroup';
                            }
                            schema['SearchPrincipalSource'] = 15;
                            schema['ResolvePrincipalSource'] = 15;
                            schema['AllowMultipleValues'] = allowMultipleValues;
                            schema['MaximumEntitySuggestions'] = 50;
                            schema['Width'] = '280px';
                            if(GroupID != null) {
                                if (GroupID > 0) {  
                                    schema['SharePointGroupID'] = GroupID  
                                }
                            }
                            SPClientPeoplePicker_InitStandaloneControlWrapper(peoplePickerElementId, user, schema);
                        });

}
  • Are you using a jslink for a client-side render? – Rothrock Sep 27 '17 at 18:18
0

The OnPreRender solution

Need to load the js scripts in OnPreRender and as it gets called on every field on the edit form so need to stop it from calling more than one. A boolean variable can be used for that. Here is the updated code.

var scriptsLoaded = false;
function loadScripts(){
    if(!scriptsLoaded){
        console.log("Loading scripts....");
        scriptsLoaded = true;
        RegisterSod('sp.js', '/_layouts/15/sp.js');
        RegisterSod('sp.init.js', '/_layouts/15/sp.init.js');
        RegisterSod('reputation.js', '/_layouts/15/reputation.js');

        SP.SOD.loadMultiple(
            ['sp.js',
             'sp.init.js',
             'reputation.js'
            ],function(){console.log("scripts loaded");}
        )
    }
}

customizeFieldRendering = function () {  
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
        OnPreRender: loadScripts,
        Templates:{
            Fields:{
                'Title':{
                    EditForm: fancyField
                }
            }
        }
    });
}; 

function fancyField(ctx){
    var fieldInternalName = ctx.CurrentFieldSchema.Name;
}

ExecuteOrDelayUntilScriptLoaded(customizeFieldRendering, 'clienttemplates.js');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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