Aug 20, 2010

SharePoint Scripts On Demand (SP.SOD)

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 SharePoint 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:

<script type="text/javascript">
// <![CDATA[
document.write('<script type="text/javascript" src="/_layouts/my_script.js"></' + 'script>');
// ]]>
</script>

True will render:
<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 notifyScriptLoadedAndExecuteWaitingJobs when 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
<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
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.
<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
<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<SharePoint:ScriptLink ID="sl" runat="server" Name="My_Script.js" LoadAfterUI="true" OnDemand="false" />
<!-- RegisterSod('my_script.js', '/_layouts/My_Script.js'); -->

<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
<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
alert('4');

function sayHello() {
alert('5');
sayHello2();
}

SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs("my_script.js");
My_Script2.js
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).

36 comments:

tenax_technologies said...
This comment has been removed by a blog administrator.
Steve Saunders said...

Note that SP.SOD is documented in the SharePoint Foundation SDK, including a code example:

http://msdn.microsoft.com/en-us/library/ff410742.aspx

Travis Lingenfelder said...

I found that you *CAN* place your script files in a subfolder of the layout folder. For example, if I had a script located at: .../14/TEMPLATE/LAYOUTS/MyCompany/Scripts/MyScript.js, the ScriptLink control would be: <SharePoint:ScriptLink ID="ScriptLink1" language="javascript" name="MyCompany/Scripts/MyScript.js" LoadAfterUI="true" Localizable="false" runat="server"/>. Without the Localizable="false" the server would look for a script at: .../14/TEMPLATE/LAYOUTS/1033/MyCompany/Scripts/MyScript.js, which does not exist and throws an exception. Adding Localizable="false" fixes the issue.

Christian said...

Hi Travis,
sure you can. But you could get into trouble when you use SOD dependencies. However, keep in mind that SP.SOD seems not to be designed for the usage of subfolders, expects of the language specific foldes.
Bye, Christian

Abe Miessler said...

Very nice post. Microsoft does not provide very good documentation on this stuff. Nice to see how/where/where everything is rendered.

Gaurav said...

Great post and a very good summary of scriptlink and scripts on demand!

Anonymous said...

Great Post

Jorge said...

Nice post!!

Colin Thornton said...

Hi Christian, this post is awesome. Few years old now but still providing excellent and relevant information.
I am struggling getting SharePoint to call SP.SOD.executeOrDelayUntilScriptLoaded twice on a single page (separate Script Editor web parts in SP13).
I have tried waiting for notification from different, dependant SODs like:

SP.SOD.executeOrDelayUntilScriptLoaded(myfunc, 'sp.ui.dialog.js');

in the first web part and then:

SP.SOD.executeOrDelayUntilScriptLoaded(myotherfunc, 'sp.js');
in the second.
Not working for me.
Do you have any pointers here?
Thanks again for the great post!

basma gaber said...

شركة تنظيف خزانات بالدمام

شركة تنظيف بيارات بالدمام

شركة تنظيف منازل بالمدينة

شركة تنظيف منازل بالدمام

نقل عفش بجدة

شركه نقل اثاث بمكة

شركة نقل اثاث بالدمام

شركة تنظيف منازل بالمدينة المنورة

شركات عزل مائي

شركة مكافحة حشرات جدة

تنظيف فلل بالدمام

شركات مكافحة الحشرات فى الرياض

افضل شركة تنظيف بالخرج




here

here

here

here

here

westerdaled said...

Hi

I am having issues similar to Colin. I noticed that some of my SP2013 pages are firing the SP.SOD.executeOrDelayUntilScriptLoaded(myotherfunc, 'sp.js'); . Weirdly, they all seem to work when I check a page out but stop when I publish

I have had a look on Firebug and I can't see sp.js loaded in certain circumstances.
Anyone seen this.

digital signature Microsoft said...

Grateful to check out your website, I seem to be ahead to more excellent sites and I wish that you wrote more informative post for us. Well done work.

Staygreen Academy said...

Attractive information, I had come to know about your blog from my friend, and let me tell you, your website gives the best and the most interesting information. Regards, SharePoint Administration Training in Hyderabad

Rakesh Parval said...

Really good piece of information, I had come to know about your site from my friend, and let me tell you, your site gives the best and the most interesting information. Regards, SharePoint Developer Training in Hyderabad

Manideep Agarwal said...

Awesome information, I had come to know about your website from my friend, and let me tell you, your blog gives the best and the most interesting information. Regards, SharePoint Online Training in Hyderabad

Kiran Joshya said...

Interesting information, I had come to know about your web-page from my friend, and let me tell you, your blog gives the best and the most interesting information. Regards, SharePoint Training Institutes in Hyderabad

Mouhamed Adawi said...

شركة تسليك مجارى بالجبيل
شركة تسليك مجارى بالاحساء
شركة تنظيف بالجبيل
شركة تنظيف بالعيون
شركة تنظيف بالهفوف
شركة تنظيف خزانات بالدمام
شركة تنظيف شقق بالدمام
شركة تنظيف فلل بالدمام
شركة تنظيف مجالس بالدمام
شركة مكافحة حشرات بالاحساء
شركة مكافحة حشرات بالجبيل
شركة تنظيف بالدمام
شركة مكافحة حشرات بالدمام
شركة رش مبيدات بالدمام
شركة تسليك مجارى بالدمام

Murray butar said...

havior of consumers and apprec

Rudolf suwiko said...

What i dont realize is in truth how youre now not actually a Krim Pemutih Pemutih Kulit Krim Pemutih Muka baju gamis pusat grosir baju Rumah Dijual Bintaro Rumah BSD Rumah Dijual BSD Rumah Gading Serpong Rumah Dijual Gading Serpong

Clement vanesha said...

of approaches to the issues youve solved Tas Grosir Batam Model Baju Wanita Jual Rumah Anggrek Grosir Tas Murah Branded Harga Tas Supplier Baju Rumah Dijual Tas Branded Terbaru Tas Batam Murah Jual Rumah Di Bsd K Jual Rumah Bsd The Fashion Korea Tas Branded Kw 1 Dijual Rumah Di Bsd Jual Baju Korea Murah Rumah Dijual Alam S Rumah Dikontrakkan Jual Rumah Di Alam Jual Rumah Di Alam Grosirtas

appdynamics vs new relic said...

Nice post ! It’ll definitely help me start contributing with the projects I use and was trying to figure it out how to help them.

Sir Poon said...

This is a situation that clobbered me for hours: I had RegisterSod('jquery.js','/_layouts/15/jquery/jquery211.js') in my master page and a duplicate RegisterSod in a Control_blah.js display template. (There was a little more to it because I use LoadSodByKey to test before registering.) I use SP.SOD.executeFunc('jquery.js',null,function() { alert('hey');}) in both places. Only the function in the master page will fire this way.

The only way I could get both to fire was to use a different SOD key in the display template. I used 'jqueryX.js' and then both would fire. This seems ridiculous but after 5 hours of messing with it and trying all sorts of things (including Mountain Dew mixed with Jolt!) I was open to doing anything.

Can someone please comment as to why the use of the same key overrides / breaks the functionality? Thanks.

Imogene sibutar said...

ng a gift of tactics which often other Jasa Rumah Bangunan Jasa Desain Rumah Jasa Desain Interior Jual Paving Jual Pasir Jual Bata Jual Hebel Jual Baja Ringan Jual Genteng Jual Besi Jasa Pasang Contblock Jasa Cor Hotmix

Sir Poon said...

I found a definitive way to load these scripts on demand as well as keep them out of the root Layouts folder.
1. Use whenever possible to register your scripts. This will ensure you get a version string appended to the end of the scripts (jquery.js?ver=asdf123) and prevent any browser cache problems from ruining your day. (Applies to CSS as well.)
2. Wherever you need to use your scripts call LoadSodByKey('key/with/path.js', null)
3. All of your js files need to call NotifyScriptLoadedAndExecuteWaitingJobs('keywithoutpath.js') after they've loaded. Google for 'preparing script libraries to work with sharepoint' or something similar.
4. Use ExecuteOrDelayUntilScriptLoaded( function(){},'keywithoutpath.js') to use the scripts.

If one script depends on another, such as bootstrap.js -> jquery.js, nest your ExecuteOrDelayUntilScriptLoaded calls.

If you need to make sure the entire page is loaded before doing anything (like correcting the page height to make room for a fixed footer), use: _spBodyOnLoadFunctionNames.push("functionNameHere")

Be sure to check whether _spBodyOnLoadFunctionNames is available before pushing to it, though.

Sir Poon said...

Well, the comment sanitizer butchered the first bullet point of my last post. It should read:

1. Use SharePoint:ScriptLink OnDemand="true" to register your scripts whenever possible...

Mossad Eladawi said...

كشف تسربات المياه
شركة مكافحة النمل الابيض بالرياض
شركة عزل اسطح بالرياض
شركة كشف تسربات المياه بجدة
شركة مكافحة حشرات بالدمام
شركة عزل خزانات بالرياض
شركة كشف تسربات المياه بالدمام
شركة مكافحة حشرات بجدة
شركة تنظيف بالدمام
شركة نقل اثاث بالدمام
شركة تسليك مجاري بالدمام
شركة نقل اثاث بجدة
شركة تسليك مجاري بالقطيف

aboshady said...

شركة مكافحة حشرات بحائل
شراء اثاث مستعمل بغرب الرياض

ahmed agag said...

شركة تنظيف فلل بالرياض
شركة تنظيف مجالس بالرياض
شركة تنظيف مجالس
شركة تنظيف مسابح بالرياض
شركة تنظيف خزانات بالرياض
شركة تسليك مجارى بالرياض
خدمات الدمام
خدمات نقل عفش بالدمام
كشف تسربات بالدمام

aboshady said...

شراء اثاث مستعمل بشرق الرياض
شراء اثاث مستعمل بشمال الرياض

شركة قمة الخليج لنقل الأثاث والتنظيف بالرياض said...

شركة نقل عفش بالرياض

شركة تخزين اثاث بالرياض

شركة تخزين عفش بالرياض

شركة نقل اثاث بالرياض

شركة رش مبيدات بالرياض

شركة مكافحة النمل الابيض بالرياض

شركة مكافحة حشرات بالرياض

Cindy Dy said...

You made some good points there. I did a search on the matter and found the majority of people will consent with your blog.

Nersha
www.gofastek.com

متولي رمضان said...


شركة نقل اثاث بالدمام
شركة نقل اثاث بجدة
شركة نقل اثاث بمكة
شركة نقل اثاث بالمدينة
شركة مكافحة حشرات بجدة
شركة رش مبيدات بجدة
شركة مكافحة الحشرات بمكة
شركة مكافحة حشرات بالدمام
شركة رش مبيدات بالدمام
شركة كشف تسربات المياه بجدة
شركة تسربات بالدمام
شركة تنظيف بجدة

متولي رمضان said...


شركة تنظيف فلل بجدة
شركة تنظيف شقق بجدة
شركة تنظيف خزانات بجدة
شركة تنظيف منازل بجدة
شركة تنظيف بالدمام
شركة تنظيف شقق بالدمام
شركة تنظيف فلل بالدمام
شركة تنظيف بمكة
شركة تنظيف وعزل خزانات بمكة
شركة تنظيف بمكة
شركة تنظيف وعزل خزانات بالمدينة المنورة
شركة تنظيف فلل بمكة
شركة تنظيف مجالس بالبخار بمكة
شركة تنظيف بالمدينة المنورة

ekhtsasy said...


شركة تنظيف فلل بالرياض
شركة تنظيف شقق بالخرج
تنظيف شقق
تنظيف خزانات
شركة تنظيف خزانات بالخرج
شركة تنظيف مسابح بالرياض
شركة صيانة مسابح
شركة شراء اثاث مستعمل بالرياض
ارقام شراء اثاث مستعمل بالرياض
شركة تنظيف بيوت بالرياض
تنظيف منازل

ekhtsasy said...


شركة تنظيف بيوت بالرياض
تنظيف خزانات بالرياض
شركة تنظيف فلل
تنظيف واجهات حجر
تسليك مجارى بالرياض
شركة نقل عفش بالرياض
شركة تخزين اثاث بالرياض
شركة مكافحة حشرات بالخرج
رش مبيدات بالرياض
مكافحة النمل الأبيض
شركة غسيل مسابح بالرياض
صيانة مسابح بالرياض
شركة تنظيف بالرياض
شركة جلي رخام بالرياض


ekhtsasy said...


شركة تنظيف خزانات بالرياض
تنظيف خزانات
افضل شركة تنظيف منازل بالرياض
شركة تنظيف بيوت بالرياض
شركة تنظيف واجهات حجر بالرياض
تنظيف واجهات حجر