Kategoriarkiv: mds

Minimal Download Strategy. Simple

There are many correct ways (1234, 5…) of making scripts work with the Minimal Download Strategy Feature (MDS) in SharePoint 2013 and 2016. But to be honest – every time I need it, I get confused. So now it is time to find a simple solution for that.

Who is better at it than the developers of the SharePoint themselves? Look at the MDS code in the built-in Display Templates:

mds-001

Let’s keep it as simple as Item_Default.js, let’s take it as it is and create our own scripts. Here is a skeletton of and MDS-ready script:

Which boils down to this in pseudocode:

  1. Execute your code
  2. Determine if MDS is enabled
  3. If MDS is enabled
  4.       Register your code for execution

That’s it. No more overcomplicating.

Related findings

External scripts (outside SharePoint Site Collection, from CDN) within ScriptBlock of a custom action (like AddJSLink in PnP)  work withou any MDS-adjustments. The ScriptBlock adds a script tag to the head of the html document, and it the js reference is added to every AjaxDelta load. I would need more time to find out why. The good news is: it is an argument for using more CDN solutions in SharePoint.

Old stuff

A while ago I wrote two blog posts about MDS. Now I realise they were overcomplicated and the solution required customizations of the master page and 3rd-party scripts.

  1. Make your javascript code work with MDS part 1
  2. Make your javascript code work with MDS part 2

 

 

Make javascript code work with Minimal Download Strategy Part 2

mds_007
Minimal Download Strategy (MDS) is an important feature in SharePoint 2013. It lets you download only a page delta, only changes. There is still issues with the MDS and custom scripts and almost no documentation on msdn or technet. In this blog post I want to learn more about adjusting custom scripts for MDS. As in my previous post, I want to take a real problem and try to solve it. The goal is to find a solution, not nececerilly the most optimal solution, at least for now.

Global Navigation and MDS

Recently I read in the Waldek Mastykarz’ blog about how to create a Global Navigation using Managed Metadata and knockout.js. These are two posts which cover this solution, where you can learn a lot from:

I wanted to try it out in my environment and test it in an MDS-enabled site. As a first step I configured it in a site without MDS. There were no problems to get it working in a site without MDS, except some changed I had to make (The final code is available on my github repository):

  • sp.js had to be loaded, because it wasn’t loaded. I added: SP.SOD.executeFunc(“sp.js”, “SP.Utilities.Utility”, …)
  • The script didn’t need to load the navigation in modal dialogs and other views with hidden suiteLinksBox

I added this to the Mavention.GlobalNavigation.init to determine if the element with id suiteLinksBox was hidden and if so, just finish the function:

Enabling Minimal Download Strategy

The Global Navigation works! Now it is time to enable Minimal Download Strategy. My site is a team site, so I can go to “Manage Site Features” and enable it:
mds_008

And… it stopped working, of course. Now the actual work begins. While troubleshooting, I discovered this:

  • MasterUrl and CustomMasterUrl have to be the same Master in order to work, otherwise MDS fails
  • with MDS knockout is not loaded, the Mavention.GlobalNavigation does not run
  • Moving the code outside the SharePoint:AjaxDelta control in the masterpage doesn’t affect anything

As previously, I tried to create a module and register it with RegisterModuleInit with no success. Maybe I’ve overseen something, but RegisterModuleInit doesn’t work in my environment.

Then I tried to wrap the whole Mavention.GlobalNavigation into a function and called it $_global_Mavention_GlobalNavigation, as it is in callout.js:

mds_002

I added $_global_Mavention_GlobalNavigation() in the end of the javascript file and I added this line of code in the master page. Unfortunately, no success. The code still didn’t run with MDS, literally, it didn’t run at all.

Breakthrough

I tried almost everything. The code started to run in MDS after these changes in the masterpage:

  • the plain <script> tags were converted to <SharePoint:ScriptLink> tags
  • In the masterpage I ran the $_global_Mavention_GlobalNavigation() again

Fortunately it started to run the code, but there was another error: ko is not defined.

Allright. I still had knockout in a plain <script> tag. So I converted it to a ScriptLink and I had to download a copy of knockout.js and provision it to the Style Library. That didn’t help much. After that I actually did the same thing with knockout as with the Mavention.GlobalNavigation code, I put everything in a function and called it $_global_knockout and invoked in the end of the script and in the script in the master page.

mds_009

The masterpage contains the following code now:

The final code is available on my github repository.

$_global_

There is a convention in SharePoint for naming these functions. But it is not necessary to use it. We can call anything. The only thing is to think about is to call it in the end of a script and in the page. Why $_global_ convention does work is this part of init.js:

Summary

In this post I have had a goal to try out a good javascript solution and try to make it work with MDS. I have used Waldek Mastykarz’ code for rendering a Global Navigation. The navigation is rendered in the masterpage through a custom script that loads data from a term store.

  • To make a custom javascript code, and this Global Navigation example particularly, work with MDS, we need:
  • Create a function (not an anonymous) and call it directly in the end of the script file
  • Use a ScriptLink instead of a plain script tag
  • Rewrite your javascript libraries like your custom javascript files

I want to learn more about the MDS feature and adjusting custom javascript code. So it maybe will be a part three.

Make javascript code work with Minimal Download Strategy Part 1

mds_001

This is a part 1 of the blog post about Minimal Download Strategy and javascript adjustments for user code. What I initially thought should be enough for one post, is not enough, so I see it as a part 1. I wrote this post after I had read Chris O’Brien’s post about JSLink Here I want investigate how we can get his accordion list view working with MDS.

Minimal Dowload Strategy or MDS is a new feature in SharePoint 2013. By now, if you read this post, you already know about it. The simplest way to see if MDS is enabled on your site, you can recognize it on the “ugly” urls. I don’t think they are so ugly. But it is a matter of taste and habit.

No matter if you like MDS or not, MDS is enabled on many site templates and is a huge step towards a faster, more responsive architecture in SharePoint, I would say, towards the Single Page Application concept in SharePoint (but it is a long way to go).

We have to keep the MDS in mind, when we write our customizations in javascript. SharePoint 2013 loves javascript and the probability is high that you write a lot of javascript. If it doesn’t work with MDS, your code breaks and the user doesn’t see the functionality, or the site owner must disable the Minimal Download Strategy feature. I wouldn’t like to have disabling of an improvement feature as a prerequisite for my code.

In this blog post I want to dig into the techniques for getting the javascript code working with MDS. For a while ago I read a wonderful blog post in Chris O’Brien’s blog:

There he describes how JSLink works and how much you can change a standard XSLTListViewWebPart. Chris creates a jQuery UI Accordion view for his list view. As an issue he mentions the MDS.

Here I want to take Chris’ code and adjust it for MDS. My goal is to change as little as possible to find the most important steps for MDS. So I’ll continue where he has finished.

My colleages who have debugged the MDS a lot, gave me a tip: $_global. The SharePoint 2013 internally uses function inside the files which starts with $_global:

mds_002

Here we have callout.js/callout.debug.js The function is called $_global and _ and the filename callout = $_global_callout. Then the function is invoked directly in the end of the file. It is a different story than the anonymous self executing funcitons we’ve seen before.

When I search the hive folder with grepWin tool, I find 148 files containing “$_global”:

mds_003

I rewrote the the code into one wrapper function and invoked in the end of file:

Unfortunately, it didn’t help. There was still no accordion. But wait, is it just the accordion that isn’t created. Indeed. The JSLink itself works. We can see it in the markup:

mds_004

Strange, maybe there was no need for rewriting the code in this case. I changed back all the javascript code to see the markup. It is the right markup. Then the problem is the accordion initialization, or the $(document).ready. Then I thought about the SharePoint-function for that: _spBodyOnLoadFunctionNames and rewrote the $(document).ready:

When I deployed it, it worked… It doesn’t seem like it is the whole solution. It is too simple. Well, it is the solution for the Accordion List View. By putting the accordion initialization code into _spBodyOnLoadFunctionNames we ensure that SharePoint runs it even on pages with MDS. As the name tells us: OnLoad. This appends the code to the onload function which runs after the $(document).ready. It means the time before the text becomes an accordion is longer.

Other cases

Allright, the actual jslink works pretty fine with MDS, except the accordion. But if we hadn’t the jQuery UI Accordion, there wouldn’t be a need to make change to the javascript code. There must be other cases where we need to adjust our javascript code. In the meanwhile I discovered a couple of files in the hive folder which use RegisterModuleInit function:

mds_005

After a quick search I found this:

Sridhar writes in his post, you have to have your javascript code in a function, then call the function inside a RegisterModuleInit. It is strange. Chris O’Brien’s example makes almost the same thing as Sridhar, it changes the display with JSLink. But there was no need for RegisterModuleInit.

More investigation will be in part 2.

Thanks to my colleagues Christopher, Björn and Martin for giving me tips and discussing it with me.