There is an issue I found when working on Sharepoint 2013. I got “SP.js” error right after published the page and cause some feature disable, such as ribbon and other scripts can not be executed. It seems that SP.js does not load properly for publishing page and anonymous users. Some articles said that sharepoint loads certain javascript files when it needs, after published the page, ribbon will close and several javasripts were unload automatically.
Actually Sharepoint provides some methods to call scripts for many conditions. So we could choose wisely among them to solved our problem. Take a look :
1) Script on Demand.
1
2
3
4
|
function sharePointReady(){
}
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', sharePointReady);
|
2) Delay until SP.js loaded.
1
2
3
4
|
function stuffToRun(){
}
ExecuteOrDelayUntilScriptLoaded(stuffToRun, "sp.js")
|
The different between 1 and 2:
SP.SOD.executeFunc(key, functionName, fn) method ensures that the specified file (key) that contains the specified function (functionName) is loaded and then runs the specified callback function (fn). Use case for “SP.SOD.executeFunc” can be that at some point you wish a JavaScript library like JQuery be loaded before you call a function defined inside it via callback function.
SP.SOD.executeOrDelayUntilScriptLoaded(func, depScriptFileName) method executes the specified function (func) if the file (depScriptFileName) containing it is loaded; otherwise, adds it to the pending job queue.
3) Load after other stuff finished.
1
2
3
4
|
function runAfterEverythingElse(){
}
_spBodyOnLoadFunctionNames.push("runAfterEverythingElse");
|
from m
When you are working with Ribbon UI extensions, Client OM or with complex SharePoint 2010 java scripts, you may noticed a Java Script class called
SP.SOD. Built-in SharePoint scripts use this class extensively. Unfortunately
SP.SOD (I guess it stands for
Share
Point
Scripts
On
Demand) is very rarely documented – until yet :)
SharePoint 2010 makes extensive use of java scripts. These scripts are located in several different files. And commonly these scripts have dependencies to functions and classes defined in other script files. Means the built-in SharePoint scripts and for sure your own scripts have to care about when which script will be loaded. And exactly this is the job of SP.SOD class! SP.SOD is defined in init.js
and will be load in the HTML head section automatically.
ScriptLink
SP.SOD works tightly together with the
ScriptLink server control.
ScriptLink is a SharePoint server control for registering java script files.
<SharePoint:ScriptLink ID="scriptLink1" runat="server" Name="My_Script.js" LoadAfterUI="true" OnDemand="false" />
In the “
Name” property you should enter the name of the script file. The control assumes that the script is located in the layout’s root folder. You could also use a relative URL instead of the script name, but cause problems with OnDemand=true. The intention is definitely to use the script name.
Putting your scripts directly into the layouts folder without a solution/feature specific subfolder seems to be against the best practice, but is required! I recommend using solution/feature prefix for the files instead of a folder.
“
Localizable” true instructs the control to search the script in the language specific subfolders of the layout’s folder (e.g. _layouts/1033/MyScript.js).
“
LoadAfterUI” determines where the script reference will be rendered in the HTML document. False inserts the reference into the HTML head. True inserts the reference at the end of the HTML body.
“
OnDemand” true specifies that the script should be loaded on demand.
False will render the following script code:
1
2
3
4
5
|
<script type="text/javascript">
// <![CDATA[
document.write('<script type="text/javascript" src="/_layouts/my_script.js"></' + 'script>');
// ]]>
</script>
|
True will render:
1
|
<script type="text/javascript">RegisterSod("my_script.js", "\u002f_layouts\u002fmy_script.js");</script>
|
As you see “true” doesn’t insert the script reference directly, instead it calls the function RegistedSod. RegisterSod is the same as
SP.SOD.registerSod(key, url). The script will not be loaded until it get explicitly requested (see SP.SOD.executeFunc)
!Instead of using SPScriptLink in a declarative way to register scripts you could also do this with some static methods of SPScriptLink in the code behind:
SP.SOD.executeOrDelayUntilScriptLoaded
SP.SOD.executeOrDelayUntilScriptLoaded(func, scriptName) schedules an asynchronous callback function (func) which will be called when the script has signaled finished loading. Signaled finished loading means that the script has called
notifyScriptLoadedAndExecuteWaitingJobs(scriptName). All SharePoint built-in scripts will call
notifyScriptLoadedAndExecuteWaitingJobswhen they have finished loading.
ExcuteOrDelayUntilScriptLoaded does not trigger loading an on demand script (SOD)!There is a very similar function pair called executeOrDelayUntilEventNotified/notifyEventAndExecuteWaitingJobs. The only diffrence is that the executeOrDelayUntilScriptLoaded/executeOrDelayUntilScriptLoaded function pair prefixes internally the scriptName with “sp.scriptloaded-“.
Example 1:
My_ApplicationPage.aspx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<SharePoint:ScriptLink ID="sl" runat="server" Name="My_Script.js" LoadAfterUI="true" OnDemand="false" />
<script type="text/javascript" language="javascript">
function myCallback() {
//sayHello is defined in MyScript.js
sayHello();
}
alert('1');
ExecuteOrDelayUntilScriptLoaded(myCallback, "my_script.js");
alert('2');
</script>
</asp:Content>
|
My_Script.js
1
2
3
4
5
6
7
|
alert('3');
function sayHello() {
alert('4');
}
SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs("my_script.js");
|
We have defined a script link for My_Script.js which will be inserted at the end of the HTML body (LoadAfterUI=true). In the inline script in the head we have registered the function myCallback to get executed when MyScript.js has signaled finished loading. The alerts will popup in the sequence 1-2-3-4. You could also wait for any built-in script to have finished loading e.g. executeOrDelayUntilScriptLoaded(myCallback, “sp.ui.js”).
You could also use the static method
ScriptLink.RegisterDelayedExecutionScript of SPScriptLink to register a delayed script execution (instead of the line: ExecuteOrDelayUntilScriptLoaded(myCallback, "my_script.js");
SP.SOD.registerSod
With
SP.SOD.registerSod(key, url) you can manual register an on demand script via JavaScript.
1
|
<script type='text/javascript'>RegisterSod('my_script.js', '/_layouts/my_script.js'); </script>
|
SP.SOD.executeFunc
SP.SOD.executeFunc(key, functionName, fn) is used to load on demand scripts (ScriptLink.OnDemand=true).
The “
key” parameter must match to the ScriptLink’s Name property
(Use small letters for key, because an issue with string normalizing in RegisterSodDep).
“
functionName” awaits a type name of an ASP.NET AJAX JavaScript class. ExecuteFunc first checks if the AJAX class has already been registered, when not it checks additionally if a SOD with this key has already been loaded and finally it will load the SOD. Load means adding dynamically the corresponding script tag to the HTML head. The check for the type helps to ensure that the script has not been already loaded via an usual script tag before. When you don’t want to work with AJAX JavaScript classes you can use “null” value for the functionName.
fn defines a callback that will be executed when the SOD has signaled finished loading.
Example 2:
My_ApplicationPage.aspx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<SharePoint:ScriptLink ID="sl" runat="server" Name="My_Script.js" LoadAfterUI="true" OnDemand="false" />
<script type="text/javascript" language="javascript">
function myCallback() {
sayHello();
}
alert('1');
SP.SOD.executeFunc("my_script.js", null, myCallback);
alert('2');
</script>
</asp:Content>
|
My_Script.js keeps unchanged.
The example is similar to example 1. The difference is that ScriptLink registers a SOD (ScriptLink.OnDemand=true) script. MyScript.js will not be loaded until it will be explicitly demanded with “SP.SOD.executeFunc(‘my_script.js’);”. When the SOD has signaled finished loading with “SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs(‘my_script.js’);” myCallback will be executed. The alerts will popup in the sequence 1-2-3-4 again.
SP.SOD.registerSodDep
SP.SOD.registerSodDep(key, dep) can register SOD dependency.
Key defines the SOD that depends on the SOD defined in
dep. When the SOD in key will be requested, the SOD dependency will ensure that the SOD defined in dep will loaded before the actual SOD defined in key. You can also define a chain of dependencyies. This means the SOD in dep can also have dependencies, and the dependencies can have dependencies too and so on. The SOD loading mechanism keeps care to resolve all the required dependencies.
Example 3:
My_ApplicationPage.aspx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<script type="text/javascript" language="javascript">
function myCallback() {
sayHello();
}
alert('1');
function myInit(){
SP.SOD.executeFunc("my_script.js", null, myCallback);
alert('2');
}
_spBodyOnLoadFunctionNames.push("myInit");
RegisterSod('my_script.js', '/_layouts/My_Script.js');
RegisterSod('my_script2.js', '/_layouts/My_Script2.js');
RegisterSodDep('my_script.js', 'my_script2.js');
</script>
</asp:Content>
|
My_Script.js
1
2
3
4
5
6
7
8
|
alert('4');
function sayHello() {
alert('5');
sayHello2();
}
SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs("my_script.js");
|
My_Script2.js
1
2
3
4
5
6
7
|
alert('3');
function sayHello2() {
alert('6');
}
SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs("my_script2.js");
|
The example registers two SODs via JavaScript (you could do this with the ScriptLink control as well) and defines that my_script.js depends on my_script2.js. When my_script.js will be requested via “SP.SOD.executeFunc(‘my_script.js’, null, myCallback);” SP.SOD will first load my_script2.js and then my_script.js. The alerts will popup in the sequence 1-2-3-4-5-6.
Summary
The idea of on demand script loading make really sense. SharePoint 2010 loads really a lot of JavaScripts - this takes time! So the idea is: first load the HTML and let it render by the browser so that the user is able to read the requested information as fast as possible. And in the second step load the behavior (the JavaScripts).
// Make sure the SharePoint script file 'sp.js' is loaded before your // code runs.