SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have javascript code included in my sharepoint site. When I load the page the first time, it is executed, but when I load it the second time, it is not running. It get's loaded in correct order but the functions inside are not executed (but only on second load)

The first time I load the page by entering the url in the webbrowser, the second time I load the page by clicking the link inside sharepoint website (same url). It seems to me that this problem occurs because it is not a complete pageload. Looks like some ajax magic to me.

This is how I have implemented the js ressources: In my aspx file I have those lines:

<asp:content contentplaceholderid="PlaceHolderAdditionalPageHead" runat="server">
<SharePoint:ScriptLink language="javascript" name="~site/SiteAssets/js/jquery.min.js" OnDemand="false" runat="server" Localizable="false" LoadAfterUI="false"/>
<SharePoint:ScriptLink language="javascript" name="~site/SiteAssets/js/newoverview.js" OnDemand="false" runat="server" Localizable="false" LoadAfterUI="true"/>
<SharePoint:CssRegistration ID="CssRegistration3" Name="<% $SPUrl:~site/SiteAssets/css/newoverview.css%>" runat="server"/>
<SharePoint:RssLink runat="server"/>

jquery.min.js

function $_global_jquery() {
    //jQuery code goes here
}

$_global_jquery();

newoverview.js

_spBodyOnLoadFunctionNames.push("runAfterEverythingElse");
function runAfterEverythingElse(){
   /*  my code */ 
   html = 'test';
   jQuery('table[summary="test"]').html(html);  
}

Take note that my code is working, as I can see it working when loading the page the first time!

The question
Why is the javascript not executed when opening the page inside sharepoint?

share|improve this question
    
Does it run too soon if you put your html modification code in side jQuery ready? I.e., $(function() { // your code } – Jussi Palo Feb 18 at 7:22
    
@JussiPalo No, I had that before but it made no difference. – Peter Feb 18 at 7:34
    
You most probably have the Minimal Download Strategy Feature enabled, disabling that is quickest way to "workaround" this issue unless you really need/want to have that enabled. – Jussi Palo Feb 18 at 7:43

If you have Minimal Download Strategy enabled, you need to do it like this:

$(function () {
      ExecuteOrDelayUntilScriptLoaded(function () {
          if (typeof asyncDeltaManager != "undefined")
            asyncDeltaManager.add_endRequest(runYourCode);
          else runYourCode();
      }, "start.js");

  });

function runYourCode() {
    //your code
     return false;
}

Source

share|improve this answer
    
The code is broken now, when I add it like this. Do I need a file called start.js or what is start.js? And do I need the return false? Do I need to modify ScriptLink attributes (LoadAfterUI etc.)? – Peter Feb 18 at 10:02
    
start.js is related to MDS, so it should be there if you use MDS. – Jussi Palo Feb 18 at 12:45
    
The code doesn't get executed now (even on first load). But it is loaded in correct order: start.js -> jquery.min.js -> newoverview.js. – Peter Feb 18 at 13:34

I see newoverview.js is included with attribute LoadAfterUI = true.

However, runAfterEverythingElse() is a <body> 'onload' event (if I understand the point of '_spBodyOnLoadFunctionNames' correctly).

So is it possible that there is a conflict between the body 'onload's firing, and the time the UI is considered 'ready', and there's a timing issue somewhere?

To test the theory out, get rid of the _spBodyOnLoadFunctionNames altogether by replacing newoverview.js's contents with:

   jQuery(function() {
       /*  my code */ 
       html = 'test';
       jQuery('table[summary="test"]').html(html);
   });

and optionally change newoverview.js's LoadAfterUI to false - this attribute shouldn't make any difference

share|improve this answer
    
I tried your suggestion but still the same error occurs. I changed LoadAfterUI to false and changed the content of newoverview.js. Code works. But only on first load. – Peter Feb 18 at 13:31
    
Sorry Peter. Frustrating. – spudnick Feb 18 at 13:40
    
A page load is a page load - it's starting from scratch each time. Therefore there should be no difference between first and second, unless: 1) a cookie has been set the first time that affects load 2, or; 2) the link you speak of from the sharepoint URL isn't a straightforward link. Verify this link is a vanilla <a href="your-page-URL"...> rather than some sneaky JS doing something else. – spudnick Feb 18 at 13:40
    
I can see that it is not a straightforward link. The page is not doing a complete reload, it is more like a partial-load. Menu on left side does not change, but the content-area is loaded again or changes. Try it yourself: open a sharepoint 2013 website and click documents or tasks on left menu. This is what I do. And most important: my javascript file is loaded (but not executed)! – Peter Feb 18 at 13:46
    
Typical MS/Sharepoint: overcomplicating everything unnecessarily In that case, I would just use a script tag in your ASPX file itself, at the bottom: <script type="text/javascript> jQuery(function() { /* my code */ html = 'test'; jQuery('table[summary="test"]').html(html); }); </script> and remove the 'push' onto _spBodyOnLoadFunctionNames (and even the ScriptLink of newoverview.js) – spudnick Feb 18 at 14:07

Long answer

Finally this is my solution to make jQuery, DOM Manipulation and MDS work alltogether in Sharepoint 2013.

aspx file

<asp:content contentplaceholderid="PlaceHolderAdditionalPageHead" runat="server">
    <SharePoint:ScriptLink language="javascript" name="~site/SiteAssets/js/jquery.min.js" OnDemand="false" runat="server" Localizable="false"/>
    <SharePoint:ScriptLink language="javascript" name="~site/SiteAssets/js/mycustom.js" OnDemand="false" runat="server" Localizable="false"/>
    <SharePoint:CssRegistration ID="CssRegistration3" Name="<% $SPUrl:~site/SiteAssets/css/newoverview.css%>" runat="server"/>
    <SharePoint:RssLink runat="server"/>
</asp:content>

mycustom.js

function myCode(){
    // jQuery code goes here
    // you can use $ namespace
}

function preCode(){
    Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(myCode);
}

if(typeof _spPageContextInfo != "undefined" && _spPageContextInfo != null){
    var jsURL = _spPageContextInfo.siteServerRelativeUrl + "/sharepointsite/siteassets/js/mycustom.js";
    RegisterModuleInit(jsURL, myCode());
}else{
    ExecuteOrDelayUntilScriptLoaded(preCode, "sp.init.js"); 
}   

Explanation

Issue 1: Partial Load (MDS)
Sharepoint Minimal Download Strategy is a feature which does a lot of caching for you and - to achieve that - does partial site loads. Which has the sideeffect of unexecuted javascript. The mycustom.js file makes use of _spPageContextInfo which will be defined when the site got loaded using mds. When that happens we need to register our script to mds to make it load - RegisterModuleInit. The script will be loaded again and JS code will be executed then.

Issue 2: Multiple events after document.ready
We can not use document.ready for dom manipulation as sharepoint is doing a lot of things after document.ready. The last event triggered is Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded which is wrapped in a function because it can't be called directly as further Sharepoint JS files need to be loaded before.

a side-note
The aspx file is loading the JavaScript files by using SharePoint:ScriptLink. I removed LoadAfterUI="true" to avoid future side effects and to have unified settings for all javascript files. Thus it defaults to LoadAfterUI="false".

Credits

  1. ASPX: ScriptLink.LoadAfterUI
  2. JS: blogs.c5insight.com (Kyle Wright)
  3. JS: josharepoint.com (José Quinto)
share|improve this answer
up vote 0 down vote accepted

Short answer

There is an alternate answer beside my long answer. But this answer is shorter, more reliable and faster. The only downside of this method: the code is executed very often.

function myCode() {
    // custom code (e.g. jQuery) goes here
} 
$("#DeltaPlaceHolderMain").bind("DOMSubtreeModified", function(event) {
      myCode();
});

Explanation

The bind method is listening for dom modification on the element with id #DeltaPlaceHolderMain. Partial reloads are doing dom mods and thus the code is being executed!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.