Archives

Archives / 2013 / October
  • The correct way to execute JavaScript functions in SharePoint 2013 MDS enabled sites

    Tags: SharePoint 2013, MDS

    Introduction

    JavaScript is the future of SharePoint development (and please don’t quote me on that :-). JavaScript is everywhere in SharePoint 2013 and upcoming incarnations, and you will see a couple of posts on this topic from me in the future. The JavaScript language is easy (well, sort of), but the many different implementations and API’s built using JavaScript might cause confusion. One of the things in SharePoint 2013 that makes JavaScript development quite problematic is the Minimal Download Strategy (MDS) in SharePoint 2013. In this post I will show you what to think of when building JavaScript features on top of SharePoint and make them aware of MDS and make them work with MDS.

    Minimal Download Strategy

    Almost a year and a half ago I wrote the Introduction to the Minimal Download Strategy (MDS) post, which since then surprisingly been one of the most visited ones on this little site! I won’t recap everything in that post, but basically MDS is a framework that allows SharePoint 2013 to download and render pages more efficient by focusing on only those parts of the page that actually needs an update. For instance, when navigating between folders in a document library, we do not need to re-render the top bar or footer etc. All this to make the perceived performance better and to reduce bandwidth.

    The Problem

    The big problem with MDS is that it only works well with the out-of-the-box stuff on a Team Site, or similar templates. As soon as you start to drop your own Web Parts, custom scripts or customizations that has not been adapted for the Minimal Download Strategy you will not see any performance benefits, au contrary you will see a performance degradation in many cases – so you turn the MDS feature off.

    One of the biggest problems is that the more and more customizations in SharePoint involves JavaScript and so far I have not seen a single non-SharePoint native script that can handle MDS that well, and I’ve been bashing my head against the wall for some time to get it to work properly. Many, if not most, JavaScripts want to execute a function when the page loads either to initialize something or to change something (haven’t we all seen all those dreaded jQuery UI customizations that could have been done with a simple CSS fix!). Common approaches to this is to use the SharePoint _spBodyOnLoadFunctionNames.push() or the jQuery $(document).ready() {} method. These methods rely on the DOM events when the page loads, so it might work perfectly fine on your first page load when MDS is enabled, since we need to fetch the full page, but on subsequent page transitions the JavaScript will not fire. An MDS page transition does not fire any DOM document load events since it asynchronously partially updates the page.

    A non MDS compatible custom field using JSLink

    List with custom JSLink columnLet’s take a look at an example using a simple Field using Client Side Rendering (or JSLink) that just makes negative numbers red and positive numbers black.

    This is how my field is defined using CAML. In this sample I create everything as a Sandboxed, purely declarative solution, but it’s easy to create the exact same solution using a SPApp or a Full Trust Code solution.

    <Field
          ID="{ce3d02df-d05f-4476-b457-6b28f1531f7c}"
          Name="WictorNumber"
          DisplayName="Number with color"
          Type="Number"
          Required="FALSE"
          JSLink="~sitecollection/Wictor/NumberWithColor.js"
          Group="Wictor">
    </Field>

    As you can see it is a standard Number field with a JSLink attribute. Next I deploy the JavaScript file, using a Module element, that looks like this:

    var Wictor = window.Wictor || {}
    Wictor.Demos = Wictor.Demos || {};
    Wictor.Demos.Templates = Wictor.Demos.Templates || {}
    Wictor.Demos.Functions = Wictor.Demos.Functions || {}
    
    Wictor.Demos.Functions.Display = function (context) {
    	var currentValue = context.CurrentItem.WictorNumber
    	if (currentValue > 0) {
    		return currentValue;
    	}
    	else {
    		return '<span style="color:red">' + currentValue + '</span>'
    	}
    }
    
    Wictor.Demos.Templates.Fields = {
    	'WictorNumber': {
    		'DisplayForm': Wictor.Demos.Functions.Display,
    		'View': Wictor.Demos.Functions.Display,
    		'NewForm': null,
    		'EditForm':  null
    	}
    }
    
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(Wictor.Demos)

    Everything is pretty straight forward. I define a couple of namespaces (which imo is a good coding practice), create a display function for my custom field, create the JSLink templates and finally registers the templates with the TemplateManager. I will not dive deep into the JSLink stuff, but if you need a really good guide I urge you to read Martin Hatch’s JSLink series.

    Once this little solution is deployed and the features activated we can add the field to a list and it should work pretty fine, unless we have MDS enabled on our site and start navigating back and forth between pages within the site. Once you navigate away from the list, containing this custom field, and navigate back using MDS page transitions it will stop using our custom template. Not funny..

    The Solution to these problems

    Fortunately there is a solution to this problem and there are two things that are really important.

    The RegisterModuleInit method

    The first reason that our field does not use the template that we defined in JavaScript is due to the fact that we register the templates with the field only when the JavaScript is loaded and executed. When navigating, using MDS, to another page this registration is reset and the JavaScript file is not evaluated again. So we need to find a way to register the module each and every time that page is used. Traditional web browsing, with full page reloads, allows us to use jQuery $(document).ready or the SharePoint function _spBodyOnLoadFunctionNames.push() to do these kind of things. But, they only do stuff when the page load event is fired – and an MDS page transition does not trigger that event.

    The SharePoint team has of course not forgotten about this scenario and has given us a JavaScript function called RegisterModuleInit(). This method is specifically designed for these kind of scenarios, we can use it to add methods that are to be executed whenever a page transition in MDS is done. The RegisterModuleInit() function takes two parameters; the first one is the path the the JavaScript file that is associated with the function to execute and the second parameter is the function to execute. One really important thing is to note that the the path to the JavaScript file must be exactly the same as used when registering it, so depending on if it’s loaded from the Layouts folder, a folder within the site etc you have to make sure to use the exact same path in the RegisterModuleInit().

    Let’s rewrite the last part of our JavaScript file and replace the line that registers the templates with these lines:

    Wictor.Demos.Functions.RegisterField = function () {
        SPClientTemplates.TemplateManager.RegisterTemplateOverrides(Wictor.Demos)
    }
    
    RegisterModuleInit(
      _spPageContextInfo.siteServerRelativeUrl + 'Wictor/NumberWithColor.js', 
      Wictor.Demos.Functions.RegisterField)
    
    Wictor.Demos.Functions.RegisterField()

    I’ve encapsulated the template registration into a new function, called RegisterField(). We then use the RegisterModuleInit() function to register this function to be executed whenever our JavaScript file is used on the page. The _spPageContextInfo object is used to get the site relative URL to which we append the relative path to where the JavaScript file is deployed. Finally we execute the RegisterField() function directly, since the RegisterModuleInit() only handles upcoming page transitions.

    If we now try this on an MDS enabled site you will quickly notice that you get JavaScript errors the second time we visit the list with this custom field, it should say something like below if you have a debugger attached or configured. In worst case MDS will notice that there is a JavaScript error and silently reload the page causing a second page load and reducing performance (you will then likely also see another JavaScript error, that we’ll talk about in a bit).

    Error: Unable to get property 'Demos' of undefined or null reference

    Looks like there’s something wrong with our namespaces!

    The Garbage Collecting issue

    The second issue requires some understanding of the Minimal Download Strategy and knowing that MDS actually has a built-in garbage collector (you didn’t see that coming right!). MDS will when doing a page transition clear up window scoped variables and delete them. This is a good thing, just imagine the number of potential JavaScript objects and structures that might have been created and stored in memory if you’re working within a site and jumping back and forth between pages. The good thing is that it will not delete objects that are properly registered as namespaces, and with that I mean Microsoft Ajax namespaces. Let’s go back to our very first sample, the one with a JSLink field. Remember I created a number of namespaces in the JavaScript file to hold my templates and functions. If I change the very first namespace definition in that file from:

    var Wictor = window.Wictor || {}

    To instead utilize the Microsoft Ajax Type.registerNamespace() function like this we will be golden:

    Type.registerNamespace('Wictor')

    Try that, redeploy your JavaScript with both the RegisterModuleInit() function and the Type.registerNamespace() declaration and you will see that (almost) everything executes just as expected. The field will render just as we want even though we navigate back and forth from the list containing the custom field.

    Getting it to work without MDS as well

    When disabling MDS on the site, or when using the “normal” URL to the list with the custom field, when a JavaScript occurs like above and on some other occasions your page will do a full page load, that is not an MDS page transition, you will get a JavaScript error that states:

    Error: '_spPageContextInfo' is undefined

    In this case the JavaScript object that we use to get the site relative URL is not created and does not exist. You will not get this error while doing MDS page transitions, since that object is created on the first page load. So how do we handle this situation?

    Since we don’t have the _spPageContextInfo object on the page, then we cannot do the RegisterModuleInit() move. But on the other hand if we get into this situation, we’re not in “MDS mode” and does not need it…clever huh! Also note, that we can get around this error by not using a site relative path and deploying stuff into the Layouts folder – but try to do that in the cloud. Let’s rewrite the last part again:

    Wictor.Demos.Functions.RegisterField = function () {
        SPClientTemplates.TemplateManager.RegisterTemplateOverrides(Wictor.Demos)
    }
    
    Wictor.Demos.Functions.MdsRegisterField = function () {
        var thisUrl = _spPageContextInfo.siteServerRelativeUrl
    		+ "Wictor/NumberWithColor.js";
        Wictor.Demos.Functions.RegisterField();
        RegisterModuleInit(thisUrl, Wictor.Demos.Functions.RegisterField)
    }
    
    if (typeof _spPageContextInfo != "undefined" && _spPageContextInfo != null) {
        Wictor.Demos.Functions.MdsRegisterField()
    } else {
        Wictor.Demos.Functions.RegisterField()
    }

    We still have a function for registering the field with the template manager, exactly the same as previously, then we introduce another method that is only used when MDS is enabled and we’re in MDS mode, that method uses the _spPageContextInfo to register the script to run for each MDS page transition. Finally we do a check in our JavaScript that if the _spPageContextInfo exists, then use our MdsRegisterField method otherwise just call the function that registers the template.

    Our full JavaScript should now look something like this:

    Type.registerNamespace('Wictor')
    Wictor.Demos = Wictor.Demos || {};
    Wictor.Demos.Templates = Wictor.Demos.Templates || {}
    Wictor.Demos.Functions = Wictor.Demos.Functions || {}
    
    Wictor.Demos.Functions.Display = function (context) {
    	var currentValue = context.CurrentItem.WictorNumber
    	if (currentValue > 0) {
    		return currentValue;
    	}
    	else {
    		return '<span style="color:red">' + currentValue + '</span>'
    	}
    }
    
    Wictor.Demos.Templates.Fields = {
    	'WictorNumber': {
    		'DisplayForm': Wictor.Demos.Functions.Display,
    		'View': Wictor.Demos.Functions.Display,
    		'NewForm': null,
    		'EditForm':  null
    	}
    }
    
    Wictor.Demos.Functions.RegisterField = function () {
        SPClientTemplates.TemplateManager.RegisterTemplateOverrides(Wictor.Demos)
    }
    
    Wictor.Demos.Functions.MdsRegisterField = function () {
        var thisUrl = _spPageContextInfo.siteServerRelativeUrl
    		+ "Wictor/NumberWithColor.js";
        Wictor.Demos.Functions.RegisterField();
        RegisterModuleInit(thisUrl, Wictor.Demos.Functions.RegisterField)
    }
    
    if (typeof _spPageContextInfo != "undefined" && _spPageContextInfo != null) {
        Wictor.Demos.Functions.MdsRegisterField()
    } else {
        Wictor.Demos.Functions.RegisterField()
    }
    

    Now, when we test this solution it should work with and without MDS enabled on the site, on all MDS Page transitions back and forth and we spare at least a handful of kittens using this code.

    Summary

    I’ve just shown you how you create a custom field rendering using JSLink that works with and without MDS. It requires you to pop in a set of additional JavaScript lines into each JavaScript file, but it is basically exactly the same JavaScript snippet each and every time. This solution does not only work for JSLink fields, it is valuable for delegate controls, web parts, ribbon customizations etc. How my life had been easier if this had been documented on MSDN twelve months ago…

    PS: If you find any situation where this does not work, please contact me and I’ll try to extend the scenario to cover that as well.

  • Clearing up the confusion with Host Named site collections and Path Based site collections

    Tags: SharePoint 2013

    Introduction

    I’ve been reading and seeing a lot of blog posts, articles, videos etc over the last few months discussion Host Named site collections vs Path Based site collections in SharePoint 2013, and 2010 for that matter. What I find interesting is that a lot of those articles are either misinterpreting the official guidance and documentation on TechNet or are just plain wrong. In this post I will try to clear up some of the confusion, and hopefully I’m not that wrong in this post. And yes, I can agree that Microsoft could have been more clear on this topic, but what’s there is actually pretty decent.

    What are Path Based site collections?

    Let’s start with Path Based site collections (PBSC) which has been the traditional method of creating and locating site collections. It’s based on the fact that you have a Web Application (IIS Web Site) in SharePoint listening to a specific host header, (1) in the picture below. Then each site collection is located relative to this host header. A site collection can only exist under (wildcard) or in (explicit) a managed path, (2) in the picture below. The URL to the site collection is the combination of the protocol, host header, the managed path and the name of the site collection. In order to have different host names, multiple Web Applications must be created, as in the example below where the Personal Sites are located on a different host name. When using Path Based site collections you configure the managed paths on a web application level,

    Path Based site collections

    The illustration above shows us how we need two Web Applications to host two different host names; one for intranet.contoso.com and one for my.contoso.com, and that we use different managed paths in the two different Web Applications.

    Path Based site collections has been the de facto, and also recommended approach, and therefore it’s the most well-known method. All configuration can be done using SharePoint Central Administration and most admins are familiar with managing Path Based site collections.

    What are Host Named site collections?

    Now, let’s take a look at Host Named site collections (HNSC). Host Named site collections have now been the “recommended” approach, very much to the fact that SharePoint Online/Office 365 uses it and it is now the most tested (by Microsoft) method. Note that this alone does not validate that HNSC should be the default method for all new deployments.

    The largest difference compared to Path Based site collections is that all site collections now have its own URL and that the web application should not listen to a host header (3), but all incoming requriest. Even though the site collections themselves have their own URL, site collections can only be created under/in a managed path. The managed paths used by HNSC are not the managed paths configured at the web application but instead they are configured on the Farm level (4).

    Host Named site collections

    One of the “myths” around Host Named Site Collections is that you cannot use managed paths, which is completely wrong. As you can see by the illustration this web application uses multiple host names and multiple farm level managed paths. You can see that we have intranet.contoso.com and my.contoso.com in the same web application. We could also add new site collections for search.contoso.com or teams.contoso.com, just as long as the DNS (and certificate) is configured correctly for the IIS.

    One of the caveats with HNSC is that you cannot configure anything of this using Central Administration. You need to use PowerShell to create the web application, managed paths and each and every site collection.

    Note: also note that the web application above have a root site collection without a site template. This is currently a support requirement. For instance see this support article KB2590564.

    Do I need to choose one of HNSC or PBSC methods?

    This is one of the largest misconceptions in this discussion. No, you do not have to choose either HNSC or PBSC. As usual with SharePoint – it depends! It depends on your requirements. For instance if you want process isolation of site collections, then you can use HNSC for the most of your site collections and then use PBSC for those who need to be in separate application pools – all you need to do is configure your DNS and the correct host headers on your PBSC. Requirements of alternate access mappings might also be a reason to think of PBSC.

    So, which method should I use then?

    My recommendation is that you always start your design with Host Named site collections. It gives you way more flexibility in the way you give host names to your site collections. You will also reduce the memory footprint of SharePoint on the web servers. Of course as always if you get bad code in your SharePoint farm which takes the application pool down – all of your sites will go down. Depending on your scalability requirements you might need to evaluate the needs of HNS and/or PBSC.

    The TechNet article referenced below contains even more details on some subtle and significant differences between HNSC and PBSC – make sure to read and understand those before starting your design. Well, you can always export and import site collections between the two methods if you need to change the structure at a later stage – but the end users will most likely not be fond of that.

    References

    Here are some important and authorative articles and posts on the topic that you should read:

    Kirk Evans, Microsoft: What Every SharePoint Admin Needs to Know About Host Named Site Collections

    TechNet: Host-named site collection architecture and deployment (SharePoint 2013)

    Summary

    I hope that this post cleared up the confusion between Host Named site collections and Path Based site collections. Which method to choose is always up to you and your requirements. I did not go into all the nitty gritty configuration details in this post, and leave that for now or to the TechNet article...

  • Office Web Apps Server: Which version is installed?

    Tags: Office Web Apps, WAC Server

    If you have been working with SharePoint you should know by now how to get the build version of an installation using PowerShell. Knowing the version of the installation is crucial for troubleshooting and knowing what features or limitations the current installation has, given the new release cadence. If you don’t know how to do it then Bing for it and then return here. But how do you do the same for Office Web Apps Server 2013?

    Retrieve the version number of an Office Web Apps Server installation

    Knowing the current version for Office Web Apps Server 2013 (WAC) is also important to know. Just as with SharePoint new features and bugs can and will be introduced over time and you need to know the version to be able to correctly get support and to patch it. Unfortunately there is not such an easy approach as with SharePoint – we cannot use the WAC cmdlets to get the current build version.

    Instead we can rely on another PowerShell method – Invoke-WebRequest. Hmm, that has nothing to do with WAC you might be thinking, which is true. But Office Web Apps returns the current version as an HTTP Header – the X-OfficeVersion header.

    In order to do use this cmdlet and to invoke an HTTP request we also need to send an anonymous request, to avoid 401’s. For this we can use one of the anonymous end-points that Office Web Apps Server exposes, for instance the end-point for the broadcast ping, like this:

    (Invoke-WebRequest https://wac.contoso.com/m/met/participant.svc/
    jsonAnonymous/BroadcastPing).Headers["X-OfficeVersion"] 

    As you can see we request the endpoint, and retrieve the specific version header from the response. This will return the current build version of your WAC farm, for instance “15.0.4535.1000” which is the August 2013 hotfix for WAC.

    Known version numbers

    I have collected the known version numbers of Office Web Apps Server 2013 on this page http://www.wictorwilen.se/WACVersions. I will try to continuously update it as the WAC server retrieves new patches and upgrades. As a bonus I also added version numbers for the version that SkyDrive currently uses (interesting!).

  • SharePoint and Exchange Forum 2013 – wrap-up

    Tags: SharePoint, Presentations, Conferences

    Stockholm ArchipelagoTwo weeks ago the ship returned to Stockholm from a 48 hour cruise on the Baltic Sea hosting the 10th edition of SharePoint and Exchange Forum. As usual the conference was a great show arranged by MVP Göran Husman and his Humandata crew. Thank You!

    We enjoyed a lot of great sessions from well-known speakers around the world and we spent the nights in the bars (and on the tables) during the nights. I had a lot of fun even though it was a bit weird having my first session just as the ship left the harbor and turned sharply – as far as I could see no one got sick, at least not from the sea.

    My session slides, and from all the other speakers sessions, can be found on the SharePoint and Exchange Forum website – http://www.seforum.se. All my demo code can be found here.

    Hope to see you next year, who knows what we will be doing then!

About Wictor...

Wictor Wilén is the Nordic Digital Workplace Lead working at Avanade. Wictor has achieved the Microsoft Certified Architect (MCA) - SharePoint 2010, Microsoft Certified Solutions Master (MCSM) - SharePoint  and Microsoft Certified Master (MCM) - SharePoint 2010 certifications. He has also been awarded Microsoft Most Valuable Professional (MVP) for seven consecutive years.

And a word from our sponsors...