2010, Development Blog, jQuery, SharePoint
_spBodyOnLoadFunctionNames in SharePoint vs. jQuery’s document ready
Since SharePoint 2013, Microsoft seems to have embraced jQuery, and you can now happily use jQuery or $ as you please in the SharePoint environment.
Click here for the SharePoint 2013 / 2016 version of this post.
In the last few months, I’ve done a lot of integration of jQuery into SharePoint for its rich animation framework. Instantiating the jQuery has always been an interesting challenge. During the branding process and masterpage creation, everything seems to work great. As time goes on and more content is added, different site types are used, etc., you can run into some interesting behaviors ranging from $ collisions and scripts not loading at all.
Follow these 2 simple rules to use jQuery in harmony with SharePoint:
Set jQuery to its no-conflict state.
This requires you to use jQuery instead of $
example:
$("#element").text("my text");
becomes
jQuery("#element").text("my text");
Use SharePoint’s _spBodyOnLoadFunctionNames array instead of jQuery’s document ready function
Why not you ask? SharePoint uses its own body onload function called _spBodyOnLoadFunctionNames which will collide with your document ready (run before or after). If you are loading your JavaScript files through the elements.xml file (through a feature in Visual Studio), this can be particularly problematic with the order of how things load.
Instead, create a function with a custom name, and push the custom name into the _spBodyOnLoadFunctionNames array. It’s wonderful and allows things to load in their proper order.
So – with examples, instead of:
$(document).ready(function() { // My custom functionality });
use:
_spBodyOnLoadFunctionNames.push("myCustomFunctionName"); function myCustomFunctionName() { // My custom functionality }
That’s it. Enjoy!
24 Comments
Mat
I know this is a very old thread but I noticed some office 365 posts so I’m assuming you are still in the game! I am very new to both JavaScript and jQuery. SharePoint on the other hand I’m very old at! So old in fact I got stuck in server side code for almost a decade but it’s what I know. I managed to avoid SharePoint for few years but I’m now back working with it. I have finally come out of my c# shell and into JS, JSOM etc etc. So I have 2 scripts, quite similar, both looking at one SPList just with slightly different CAML queries. My issue I cannot for the life of me get the 2 scripts working on the same page. My what seems like endless digging, has lead me here. I have my scripts stored in the asset Library on SPS2103 and I am referencing in 2 CEWPs. Each CEWP will live quite happily on an SPPublishing page individually whereas when I add the other CEWP to the same page the trouble starts with various results. Either: 1 works as expected, the other doesn’t load or 1 doesn’t work, the other the loads same query twice. So I read your article and all the comments you have kindly responded to and I am hoping you can help.
So I have tried various things: 1. Made sure there are no identical elements declared. 2. Even changed the CSS ids for each script in a more desperate maneuver 3. Changed $ to jQuery 4. Declared a var to equal jQuery.noConflict() 5. Added true! to 4 hehe!
No luck on any of it. Do you have any suggestions? Have you experienced this issue before or even since 2011!!?!
Stephan
Hi Mat,
Apologies for the delay in response – I’ve been quite swamped myself 🙂 Hopefully this still finds you in time.
Without the code you’re working on, I’m working on a few assumptions, so apologies if I’ve misunderstood your situation.
SharePoint 2013 is quite forgiving with jQuery, so you can use it native (no need to replace $ with jQuery). Regular JavaScript rules still apply though – if you have 2 separate script files, ensure that your function names and variable names are all different. JavaScript is always global, so if you have the same variable or function names in different files, whichever one loads last will overwrite the previous one, and also eradicate any uses of it (so if the first function was assigned to a variable, if the function gets overwritten, the variable also becomes useless).
For that reason, I wrote this article: this article to make JavaScript a lot easier in SharePoint. You basically create a single, strongly-typed variable to put everything into, and use a different one for each file – that way you only have to ensure that one top-level object name is unique and whatever is inside can be simple and descriptive.
Another thing to check is how jQuery is loading – this can also cause issues like what you’re describing. JavaScript loads when the network handler gets to it, so the jQuery library will load at different times. It’s still good to put the scripts in order of dependency, but I always do additional dependency checks. Sometimes you’re also working in an environment where jQuery is already called on a page, and you want to use a different version, or ensure it loads in any instance, which is why I wrote this article to update the one you found with the newer versions of SharePoint. This is my go-to for doing any JavaScript in classic SharePoint 2013 & 2016. A good way to check this is to view the source of your page (so you can see the HTML that SharePoint rendered) and search for “jquery” – if you find that file loading more than once, you’ll need to fix it. You can also use your Console (F12) Network tool to see if jQuery is being loaded more than once. This can definitely cause problems and is my #1 bane with JavaScript development on servers where others have “had a go” 😉
Things are now vastly different in Office 365, but that’s another can of worms 🙂
Hope this helps you troubleshoot and hope you figure it all out!
Stephan
Jon
Thanks Stephan. Found this through a Google search. Helped to remember the approach. Miss working with you! Hope all is well.
Stephan
Jon you rockstar! You’re the inspiration for this blog! Miss working with you too!
prasad
Hi Stephan,
your first section helped me !!!
“Set jQuery to its no-conflict state.” use jQuery instead of $.it was creating problems for me in my newform.aspx in my sp 2010 splist . i have used sputility.js and prototype.js file and it seems that , $ sign has a MAJOR conflict with document.ready function.
I changed from $ to jquery and it started reading the values from the newform.aspx using sputility.js file and its api .
Thanks very much!
Vespira
Thanks you for the tip !
I’m currently working on a similar project, and I want to use jQuery for design purposes. However, it appears that the element I’m trying to access via the DOM methods is not processed yet at page load. So, I tried window.load or document.ready protections, with no success. Then I tried your method, but my custom function added to the BodyOnLoad event is not called …
code more worthy than explanations :
$.getScript(“/sites/archimen/_layouts/15/sp.js”);
_spBodyOnLoadFunctionNames.push(‘defaultVisibility’);
function defaultVisibility() {
console.log(“test”);
}
If someone got time to answer me, thanks in advance !
stephan
Hi there,
I placed your code inside my PlaceHolderMain content placeholder:
<asp:Content ContentPlaceholderID="PlaceHolderMain" runat="server">
<!– other code –>
<script type="text/javascript">
_spBodyOnLoadFunctionNames.push('defaultVisibility');
function defaultVisibility() {
console.log("test");
}
</script>
<!– other code –>
</asp:Content>
and it worked just fine.
A few things to keep in mind:
1. certain versions of IE do not output console.log commands, so you can replace that test with alert(“test”) instead and try again.
2. critical JS errors elsewhere will stop JS from continuing (so this code will never fire if there is an error).
3. the page has to call the supporting JS files – a safe and easy way is to wrap it with the standard masterpage.
Hope that helps 🙂 Let me know your findings when you figure it out.
mr harrison
Thanks Man!!
JerryC
awesome – THANK YOU! Just what I needed to know
Johannes
Hi Stephan
Thanks for the article, it almost helps me, but was hoping you might have a suggestion to help me all the way to my goal…
For my purpose _spBodyOnLoadFunctionNames isn’t always good enough, because it fires the functions when the body has loaded. But I have some reports in my sharepoint that takes some time to load, which means that not only do I have to wait for the body to load, I also have to wait for those web parts to load completely before I can run the functions I wish (which is adding some class tags to certain rows in the report table).
Is there a similar array that will fire the functions when all the web parts of my have loaded? Or do you have a suggestion to a work around
stephan
Hello Johannes,
Sorry for the late reply – I’ve been really busy on a new contract. I hope you found your answer in the meantime 🙂
Not knowing too much about your specific project, I’m making the assumption that the data is loaded dynamically by SharePoint via AJAX.
One option which I’m assuming will probably not work but worth mentioning is to use ExecuteOrDelayUntilScriptLoaded. You pass it the function name you want to run after a specific JS file is loaded. This is helpful if you need to grab the SP.ClientContext object. It looks like this:
ExecuteOrDelayUntilScriptLoaded(yourFunctionName, "lastDependencyForYourFunction.js");
function yourFunctionName () {
// Do stuff
}
The other method which might be more reliable is to use good old fashioned JavaScript (or jQuery to simplify the example) to check if the content is there with a function that calls itself through a setTimeOut script. I think that this might work better because you know the tags to go after to style your rows (adding class tags) and since you know that, you can check to see if they exist (and if there are multiple web parts, see if they exist within certain web part IDs)
Something like this:
// Set up a custom jQuery variable
$sr = jQuery.noConflict();
// Fire the function when jQuery has been loaded
// PS - we do not need to wait for _spBodyOnLoadFunctionNames since we only need the jQuery framework and are looking for a classname or ID
$sr(document).ready(function() {
checkIfItemLoaded();
});
function checkIfItemLoaded() {
// If the item exists
if ($sr("#IDToCheckExists").length > 0) {
// Do your magic
} else {
// Item not loaded yet, try again in 0.5 seconds
setTimeout(checkIfItemLoaded,500);
}
}
Really hope this helps – if this doesn’t work, you might have to give me some example code to work with – I’m making broad guesses on your situation 🙂
Have a great weekend!
Harald
You are my HERO! 🙂 Tnx a lot!
Ling
Hi Stephan,
I was working on sharepoint site coredesign.master and need a little bit custom on this page.
I need to remove the inline style generated by js somewhere for this tag:
To do this, I added javascript after tag. Below is what I added:
_spBodyOnLoadFunctionNames.push(“myCustomFunctionName”);
function myCustomFunctionName() {
$(“#s4-workspace”).removeAttr(“style”); // My custom functionality
}
This suppose to remove the padding-top for the div #s4-workspace. However, it does not do anything.
Could you let me know what I did wrong?
Thank you!
Ling
stephan
Sorry for the lag in reply Ling, I’ve been a little swamped at work lately. If you haven’t gotten your answer by now, here is my suggestion:
Your code will only remove the style='...' from that node. #s4-workspace has other styles associated with it in the core4.css file, which you need to override.
If you want to remove the padding, you have to override it using css in jQuery. I'm using the attr() tag to add a style attribute to the #s4-workspace tag instead of .css() because of the !important clause, necessary to override some styles (using jQuery instead of $):
_spBodyOnLoadFunctionNames.push(“myCustomFunctionName”);
function myCustomFunctionName() {
jQuery('#s4-workspace').attr('style','padding-top: 0px !important');
}
Hope this helps! 🙂
Nisha
I am using SP2010 and need to run some javascript code when the page loads. Due to this, I have used the following method _spBodyOnLoadFunctionNames.push(“myfunction”) to execute the javascript function. The problem is that the page loads (and the original html/css elements are loaded), then the page reloads with the newly updated javascript code. how do we eliminate the delay?
Thanks.
stephan
Hi Nisha,
To be clear, I’m guessing by “reload” you mean that adjustment that happens after page render. The short answer is a basic decision tree:
– If it’s a SharePoint control AND has SharePoint adjusting it with JavaScript (like the content area of a v4.master), then use _spBody….
– If it’s a static SharePoint control (rendered by SharePoint but has no JavaScript attached to it), then you can use jQuery
– If it’s a custom web part, user control or content that you created, you can safely use jQuery
I hope this helps – if your decision still isn’t clear, please elaborate on what you are adjusting (and how) and feel free to send screenshots or more details over email – [email protected].
Have a great day! 🙂
BGM
Thank you! I needed to hide certain elements in my sp page, but needed to wait until the document was ready before I could interact with them. Using document.ready would not work, but this works very well! Just what I needed!
stephan
Glad to hear it! 😀
Christophe
Stephan, thanks for your useful article. I was wondering if you could elaborate on why there is a collision risk. I actually left a question on a SharePoint forum about this, and was redirected to your post:
http://sharepoint.stackexchange.com/questions/30500/risk-of-conflict-between-jquery-document-ready-and-spbodyonloadfunctionnames
I also asked on the jQuery forum:
http://forum.jquery.com/topic/document-ready-and-body-onload-on-the-same-page
stephan
Hi Christophe,
(fyi – the summarized answer is in the last paragraph 😉
I’ve used jQuery(document).ready(…); in SharePoint, but always prefer to use what’s already there. SharePoint has a few things already attached to body load, which can negatively interact with your jQuery (depending on what you’re doing). One proven example is sizing detection or change (height/width). On body load, SharePoint manually sets the height of its #s4-bodyarea (when v4.master is used) to whatever the viewport height is, minus the space the browse and Site Actions bars take up. That same script also runs on window resize.
I don’t recall exactly the case I had for this, but I also ran into an issue with older browsers triggering the jQuery(document).ready(…), even though the page hasn’t rendered yet – SharePoint has around 750KB of JavaScript that has to load and execute on each page load, which can slow down the render process, however I think you’ll still run into this issue with whichever you use. This is also an issue when doing DOM manipulation (adding or removing from the DOM).
That said, I use jQuery(document).ready(…); very sparingly – but I do use it. I’ve implemented custom top-navigations (instead of the OOB top nav) to get the navigation drop-downs to be available immediately. One massive shortfall of _spBodyOnLoadFunctionNames is that it will wait for the ENTIRE page to load. If, for instance, you are loading images from another system that tends to be slow, SharePoint will wait for everything in the DOM to finish loading in before it will traverse the array. jQuery(document).ready(…) will load immediately when the page is rendered.
That’s a lot of examples (I like to share knowledge thoroughly 😉 – it’s my opinion that you can use them interchangeably, but it depends heavily on what you are doing. If you are deploying a control that is fully yours, you should be able to use jQuery(document).ready(…) – however if you’re interacting with third party or OOB functionality, I would lean on spBodyOnLoadFunctionNames instead.
Stephan
tomc
Thanks. This saved me a ton of time. One question. from a jQuery novice: Is there any performance difference between $(…) and JQuery(…)? Thanks again.
stephan
Hi tomc,
From my knowledge there is no performance difference between using $(…) or jQuery(…). I prefer using jQuery(…) purely to prevent code conflicts. A few JavaScript libraries out there all use $(…), which in some cases can override each others’ functions/methods and cause a mess for you (this is a common occurance in some SharePoint sites).
If you use jQuery.noConflict();, you ensure that jQuery is running in a mode where it is in its own namespace and will not mess with other libraries running on the same page (as you’re aware I’m sure – using jQuery.noConflict will render $(…) non-functional).
I’m really glad you found some value in my blog. I love to share my knowledge and enjoy helping out the community! Thanks for the kind words. 🙂
Stephan
Christophe
“$” is one character, “jQuery” is 6 characters… so obviously if you use jQuery instead of $ in your script, it will take longer for your browser to load it.
Note that you can also define your own variable:
var $1_7_2=jQuery.noConflict(true);
stephan
Christophe – thank you very much for the contribution – I have found a lot of value in creating my own namespace – this is very handy and will ensure no collisions with other frameworks using the same namespace.
Thank you Christophe!