When running the
SP.UI.Status.addStatus command upon page load, the status message was being hidden almost immediately in Chrome but worked as expected in IE.
SP.UI.Status.addStatus and was initially implemented as follows (the script is being rendered dynamically using an ASP literal control, I’ll just be considering the final output):
This worked as expected in IE, however the status message would appear for a split second and then disappear in Chrome.
The first piece of the the puzzle: What is happening?
After getting deep with Chrome DevTools I found the script responsible for hiding the status message. SharePoint utilises the
document.onreadystatechange handle to run a function called
fnRemoveAllStatus. I think you can guess what it achieves. Why this is being run at this point is beyond me. Importantly, I don’t want to prevent it running in case it serves a purpose that I’m unaware of.
The second piece of the the puzzle: How’s that work?
If a function is assigned to
document.onreadystatechange it will be run as many as four times (depending on when in the cycle the assignment occurs), once for each transition between the following sequence of states:
Good practice would have the function check for the current state and only act once, when in the correct state. Naturally this logic is absent from the
The third piece of the the puzzle: What is running when?
The difference between these options in regards to what we have just discussed is that
ExecuteOrDelayUntilScriptLoaded run when
document.readyState is ‘interactive’ whereas
$(window).load runs when
document.readyState is ‘complete’.
Laying the final puzzle piece: Why’s it working in IE but not Chrome?
When running the code in IE, rather than executing the script block during the ‘interactive’ readyState is was being executed after transitioning to the ‘complete’ readyState and this meant that is was running after the
fnRemoveAllStatus call as we desire. I believe this happens because the sp.js file is being added via a script link control with ‘LoadAfterUI’ set to true which is only understood by IE. I haven’t investigated this last comment, if I am wrong please leave a comment about it below.
So, the solution is rather simple once you have this understanding. Wrap the command in
$(window).load to ensure it occurs after the
fnRemoveAllStatus method is called during the transition into the ‘complete’ state. Like this:
ExecuteOrDelayUntilScriptLoaded will also load scripts which are marked to load on-demand. If you are testing in Chrome you may begin to believe it unnecessary to use
ExecuteOrDelayUntilScriptLoaded when using
$(window).load as all scripts have loaded by then. This is true for browsers other than IE. In IE we must use this function to ensure that the script is loaded at all.
As a final note I’d like to add that apart from this specific case I would suggest using
$(document).ready rather than
$(window).load as it will mean that the page loads faster (unless of course your script requires all resources to be loaded before acting. e.g. you are working with images of undefined sizes).