I know there are many posts on the subject of dynamically loading SP files. I've tried so many of them, but none of them seem to work. As I was trying to solve an issue I realized I had to back up and ask a lot of questions to understand what is going on.
TL;DR is there a way to make sure that required files are loaded once (and only once) in a specified order before code executes.
Otherwise, here are my my questions.
First question
What is the difference between the SP.SOD functions and those with out that prefix? I find documentation and examples that use either one or the other and often mixes both.
- SP.SOD.registerSod vs RegisterSod
- SP.SOD.executeOrDelayUntilScriptLoaded vs ExecuteOrDelayUntilScriptLoaded
- ??? vs EnsureScriptFunc
- SP.SOD.executeFunc vs ???
- SP.SOD.loadMultiple
- etc....
As best I can tell the ones prefixed with SP.SOD need to have a scriptlink placed on the masterpage? Is that correct? So if I can't update or change my masterpage then I should use the versions without SP.SOD?
The problem with loadMultiple
For awhile we have been using the following code to load the files needed:
SP.SOD.loadMultiple(
['sp.core.js',
'sp.runtime.js',
'sp.js',
'~sitecollection/_layouts/15/autofill.js',
'~sitecollection/_layouts/15/clientpeoplepicker.js',
'~sitecollection/_layouts/15/clientforms.js',
'~sitecollection/_layouts/15/clienttemplates.js'
],
function(){...init the people picker, etc...}
);
The problem with this is that it always loads those files even if they have already been loaded. This causes problems with SP.ClientContext
which is in sp.js. If that gets loaded twice it causes all kinds of problems. But we want to be sure that we don't try and load the autofill and clienttemplates before the require "core" files.
How do we make sure that the later files load after the "core" -- and by core I mean the ones that seem like they are what really makes SP work -- sp, sp.core, and sp.runtime.
Partial solution for one file
This blog post explains what I seem to experience as the behavior of the SP.SOD functions.
executeOrDelayUntilScriptLoaded: executes the code if/when the referenced script is loaded. Does not load the script. executeFunc: loads the script and executes the function. "... if the script associated with the script key is already loaded, then executeFunc does absolutely NOTHING."
In order to be sure they are already loaded or loaded because they are needed, the author combines both methods like this. (I assume that he actually prefixed those with SP.SOD, right?)
executeOrDelayUntilScriptLoaded(function()
{ ... code ... }, "myScript.js");
executeFunc("myScript.js", null, null);
I'm not quite sure how I could combine that approach for the seven required files. And if that would be readable or maintainable code.
RegisterSodDep
In my quest to find a solution I came across this blog post which suggests using RegisterSodDep
instead of multiple nested EnsureScriptFunc
. when I tried this it didn't work as I had hoped, but I saw how I could combine it with the solution about. This is my final code
//register the urls for the require files
SP.SOD.registerSod('autofill.js',Srch.U.replaceUrlTokens("~site/_layouts/15/autofill.js"));
SP.SOD.registerSod('clientpeoplepicker.js',Srch.U.replaceUrlTokens("~site/_layouts/15/clientpeoplepicker.js"));
SP.SOD.registerSod('clientforms.js',Srch.U.replaceUrlTokens("~site/_layouts/15/clientforms.js"));
SP.SOD.registerSod('clienttemplates.js',Srch.U.replaceUrlTokens("~site/_layouts/15/clienttemplates.js"));
// register the dependencies
SP.SOD.registerSodDep('clienttemplates.js','sp.js');
SP.SOD.registerSodDep('clienttemplates.js','sp.core.js');
SP.SOD.registerSodDep('clienttemplates.js','sp.runtime.js');
SP.SOD.registerSodDep('clienttemplates.js','autofill.js');
SP.SOD.registerSodDep('clienttemplates.js','clientpeoplepicker.js');
SP.SOD.registerSodDep('clienttemplates.js','clientforms.js');
// if it isn't already loaded wait until it is loaded
SP.SOD.executeOrDelayUntilScriptLoaded(function(){
}, "clienttemplates.js");
// load templates if it isn't already loaded otherwise do nothing
SP.SOD.executeFunc("clienttemplates.js", null, null);
This seems to work for the current page and site -- but I've said that before about other approaches to the issue.
Does this solution seem like it will meet my criteria of making sure that all the files are loaded (only once) and in the correct order? Any issues that folks can see with this solution?