_spBodyOnLoadFunctionNames in SharePoint vs. jQuery’s document ready

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 > span").text("my text");

becomes

jQuery("#element > span").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!

This article has 16 comments

  1. awesome – THANK YOU! Just what I needed to know

  2. 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

    • 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!

  3. You are my HERO! :) Tnx a lot!

  4. 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

    • 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! :)

  5. 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.

    • 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 – stephan@stephanrocks.com.

      Have a great day! :-)

  6. 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!

  7. 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

    • 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

  8. Thanks. This saved me a ton of time. One question. from a jQuery novice: Is there any performance difference between $(…) and JQuery(…)? Thanks again.

    • 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

    • “$” 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);

      • 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!

Leave a Reply