Search This Blog

Minimum Download, Maximum Frustration

So, Microsoft keeps pushing SharePoint devs to use JavaScript in SharePoint 2013, but then we have the "Minimal Download Strategy" which basically causes a great deal of your custom JS to break.  Here's what I learned about MDS . . .


The project was a combination of a publishing site as the root of the intranet with team sites for each department.  By default, SharePoint turns MDS on for team sites, but the feature is off and not supposed to work on publishing sites.  However if MDS is turned on in a publishing site, the failover mechanism of MDS still works.  This means that MDS will never work correctly on your publishing site.  If you turn it on, however, it can make some of your pages load more slowly.  The flow is something like this:
  1. Welcome – does failover (starts to go to MDS redirect but reverts back)
  2. Other Site Pages – does failover, MDS not working
  3. List pages – goes straight to page, no failover, no MDS
  4. Team Site sub site under the Publishing portal - MDS works correctly
With MDS enabled and working as expected, I found that quite a bit of our custom scripting had either stopped working or was working sporadically.  The first issue is how your refer to scripts in the master page.  Script tags will no longer work.  This is true of custom scripts as well as those SharePoint provides.  So, the first fix was to use ScriptLink tags with OnDemand set equal to "true."


<SharePoint:ScriptLink Name="CustomPath/jquery_1.10.2.min.js" runat="server" OnDemand="true"/>


This crucial "OnDemand" setting basically lets MDS decide when to load scripts.  I was not pleased with its decision making abilities.  The libraries needed were not loading successfully, so additional JavaScript had to be added to force the libraries to load when needed.  After trying several options presented on the web, I found that LoadSodByKey was the method that got the job done.
This allowed the script to run (primarily noticeable by a custom menu) when the page loaded.  However, it seemed that if you clicked on one of the items in SharePoint's left hand navigation area, the menu stopped working.  Apparently, on these links, MDS did not find it necessary to load these custom scripts again.  In order to make the menu work on every page, the LoadSodByKey method had to be added to the endRequest handlers of the asyncDeltaManager (an object created and used by MDS).

      if (typeof asyncDeltaManager != "undefined") {

                ExecuteOrDelayUntilScriptLoaded(function () {

                        asyncDeltaManager.add_endRequest(initScript);

                }, "start.js");


In the initScript method, LoadSodByKey had to be called once for jQuery, with nested calls to load Bootstrap and a custom .js file that both used jQuery.  This proved a little tricky with Boostrap since there is no named function as an entry point.  Passing null for the second argument seemed to fix it.  This solved all of the problems except for one.  The content search web part was using a custom display template that loaded jQuery and jQuery UI.  Even though the script was being loaded on the page, it was somehow not "filtering down" into the web part.  So one more line had to be added to make sure the script was available to load in the web part.


RegisterModuleInit("CustomPath/jquery_1.10.2.min.js", null)


So now, after adding all these code JavaScript code statements (full code from the master page below) to make other JavaScript load when it was supposed to, we were finally back to the point we were when MDS was turned off.  That seems like a lot of unnecessary effort just to get your custom script to work.  This is why I've often seen MDS simply be disabled.  Have you had to use any other workarounds to make MDS play nice?


<script type="text/javascript">            //<![CDATA[
            RegisterModuleInit("CustomPath/jquery_1.10.2.min.js", null)

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

                ExecuteOrDelayUntilScriptLoaded(function(){
                    asyncDeltaManager.add_endRequest(menuCollapse);
                }, "start.js");
            }
            else {
                initScript();
                menuCollapse();
            }
            function initScript()
            {
                var g_pageLoadAnimationParams = { elementSlideIn: "sideNavBox", elementSlideInPhase2: "contentBox" };
                
                LoadSodByKey("CustomPath/jquery_1.10.2.min.js",
                    function () {
                        $(function () {
                           LoadSodByKey("CustomPath/bootstrap.min.js", null);
                            
                                    LoadSodByKey("Custom.SharePoint.Branding/Custom.js",
                                    function () {
                                        getStockTicker();
                                    }
                                    ); 
      
                        }) //end bootstrap
                }); //end jquery
            } //end initscript