Techblog

Herzlich Willkommen im Communardo Techblog, dem Entwickler-Weblog von Communardo. An dieser Stelle werden Ideen, Problemlösungen, Tipps und Problemstellungen rund um die Entwicklung webbasierter Software vorgestellt.

techblog-teaser

SharePoint 2013: JSLink – Problemfall Minimal Download Strategy (MDS)

, von

Teil 1: JSLink: you’ve got the whole SharePoint in your hands
Teil 2: JSLink: was man sonst noch wissen sollte
Teil 3: JSLink – Problemfall Minimal Download Strategy (MDS) (dieser Artikel)

SharePoint 2013 bietet mit JSLink die Möglichkeit, die Bedienoberfläche für den Anwender vergleichsweise einfach anzupassen. Dabei kommt kommt JavaScript zum Einsatz, welches die Oberfläche clientseitig verändert.

Im Zusammenhang mit der Minimal Download Strategy (MDS) kann es passieren, dass per JSLink eingebundene Skripte nicht ausgeführt werden. Die MDS ist eine – ebenfalls neue – Technik, um die mit dem Server ausgetauschte Datenmenge zu reduzieren.

Der Beitrag zeigt anhand eines einfachen JSLink-Anwendungsfalls, welche Fallen es im Zusammenspiel mit der MDS gibt und wie Skriptcode aussieht, der diesen aus dem Weg geht.

Was ist die Minimal Download Strategy (MDS)?

Mit der neu eingeführten MDS reduziert SharePoint 2013 die Menge der bei einer Seitennavigation zwischen Client und Server ausgetauschten Daten. Seiteninhalte, die sich nicht ändern, müssen auch nicht neu übertragen werden.

Auf dem Server wird die Differenz (Delta) zwischen der aktuell angezeigten Seite und einer neu angeforderten Seite berechnet. Nur dieses Delta wird an den Client geschickt, der damit die alte Seite zur neuen Seite umformt. Und das alles per JavaScript.

Für welche Sites das MDS-Feature standardmäßig aktiviert ist und welche Magie bei der Seitennavigation im Detail passiert lässt sich auf den folgenden Seiten nachlesen:

Woran erkenne ich eine MDS-Navigation?

Die MDS ist standardmäßig in Team Sites, Blogs und einigen weiteren Site Templates aktiviert. In Publishing Sites ist sie deaktiviert. Darüber hinaus kann SharePoint in Einzelfällen entscheiden, die MDS zu deaktivieren.

Woran lässt sich erkennen, ob eine Seitennavigation mit aktivierter MDS durchgeführt wurde? An der URL.

Hier die URL einer Team Site-Startseite mit aktiver MDS:

mds-url

Die Seite start.aspx dient als Container, der alle Basiselemente einer Seite enthält. Sie lädt außerdem die Skripte, die das vom Server empfangene Delta verarbeiten und die Zielseite zusammenbauen.

Hier dagegen die URL einer Team Site-Startseite ohne MDS:

non-mds-url

Die URL sieht “normal” aus.

(Sollten Sie im Browser einen Redirect von einer “MDS-URL” auf eine “Nicht-MDS-URL” beobachten, dann hat SharePoint in den failover-Modus geschaltet und die MDS-Navigation abgebrochen. Das kann bspw. durch Skriptfehler in JSLink-JavaScript-Dateien verursacht werden.)

An der URL einer Seite lässt sich also erkennen, ob die MDS für einen Navigationsvorgang aktiv war oder nicht.

Ohne MDS ein Erfolg: Anpassung einer Listenansicht per JSLink

Unser Test-Anwendungsfall: Wir entfernen die Überschrift eines Listenwebparts per JavaScript, welches per JSLink an den Webpart gebunden wird.

Im Beitrag “JSLink: You’ve got the whole SharePoint in your hands” wurde bereits gezeigt, welche Macht JSLink für die Anpassung der Oberfläche besitzt.

In einer neuen Team Site dient der “Documents”-Webpart als Versuchsobjekt. Dieser befindet sich auf der Startseite der Team Site:

team-site-documents-webpart

Das Ziel: die Überschrift “Documents” entfernen. Dazu benötigen wir eine JavaScript-Datei, die den passenden Code enthält:

// mdstest.js - JSLink file for web part<br />Demo = (typeof Demo != "undefined") ?  Demo : {}<br />Demo.hideWebpartTitle = function()<br />{    <br />    document.getElementById("WebPartWPQ2_ChromeTitle").style.display = "none";<br />}<br />Demo.hideWebPartTitle();

Das HTML-Element mit der ID “WebPartWPQ2_ChromeTitle” enthält den Titel, also holen wir uns dieses Element und blenden es aus. Die Funktion hideWebpartTitle platzieren wir dabei im Namespace Demo, um den globalen Namensraum nicht zu verunreinigen.

Die Datei speichern wir als “mdstest.js” und laden Sie in die Style Library hoch:

mds-js-file-style-library

Anschließend binden wir die Datei per JSLink an den XsltListViewWebpart, der für die Darstellung der Documents-Liste verantwortlich ist.

JSLink lässt sich in den Webparteigenschaften konfigurieren:

mds-xsltlistviewwebpart-jslink

Wir verwenden den Platzhalter ~site um den Pfad zu unserer .js-Datei relativ zum Web zu adressieren. (Weitere Platzhalter finden Sie in diesem Beitrag.)

Nach dem Speichern des Webparts und der Seite laden wir diese mit F5 neu. Und wir sehen den gewünschten Effekt, der Titel ist ausgeblendet:

mds-webpart-title-hidden-with-jslink

Mit MDS funktioniert nichts mehr (vorerst)

Wir lösen eine MDS-Navigation aus und stellen fest: unsere per JSLink an den Webpart gebundene JS-Datei wird nicht mehr ausgeführt. Der Webparttitel bleibt also sichtbar.

Die MDS-Navigation lässt sich wie folgt auslösen: im Schnellstartmenü wählen wir einen beliebigen anderen Menüpunkt und anschließend wieder den Ursprungs-Menüpunkt “Home”.

mds-navigation

Schauen wir uns den “Documents”-Webpart jetzt an, dann sehen wir, dass der Titel noch vorhanden ist. Unser Script wurde also nicht ausgeführt:

team-site-documents-webpart-title

Laden wir nun die Seite neu, verschwindet der Webparttitel wieder:

 

 mds-f5-jslink-fix

Dieses Spiel lässt sich beliebig wiederholen.

Die Regeln der MDS

Der Grund, warum unser Skript bei MDS-Navigation nicht aktiv wird ist: wir haben die Regeln der MDS missachtet.

Die MDS beinhaltet ein Opt-In-Modell für Navigationsereignisse. Skripte, die bei einer Navigation ausgeführt werden sollen, müssen registriert werden. Darüber hinaus verwendet die MDS einen Garbage Collector, der den globalen Namensraum reinigt. Werden Objekte im globalen Namensraum platziert (wie unser Demo-Objekt), dann werden diese u.U. entfernt. Um dem zu entgehen, müssen Objekte als Namensraum registriert weden.

Wir passen unser Skript diesen Regeln an und das Ergebnis sieht so aus:

Type.registerNamespace("Demo");<br />Demo = (typeof Demo != "undefined") ?  Demo : {}<br />Demo.hideWebpartTitle = function()<br />{    <br />    document.getElementById("WebPartWPQ2_ChromeTitle").style.display = "none";<br />}<br /><br />Demo.start = function() {<br />    Demo.hideWebpartTitle();<br />};<br /><br />Demo.mdsStart = function() {<br />    var thisUrl = _spPageContextInfo.siteServerRelativeUrl + "/Style Library/mdstest.js";<br />    Demo.start();<br />    RegisterModuleInit(thisUrl, Demo.start);<br />};<br /><br />if (typeof _spPageContextInfo != "undefined" && _spPageContextInfo != null) {<br />    // running under MDS<br />    Demo.mdsStart();<br />} else {<br />    // not running under MDS<br />    Demo.start();<br />}

Die Registrierung unseres Namensraumes “Demo” schützt ihn vor dem Garbage Collector:

 Type.registerNamespace("Demo");

Die Registrierung unseres Skripts mittels RegisterModuleInit ist notwendig, damit dieses auch bei MDS-Navigation aufgerufen wird:

RegisterModuleInit(thisUrl, Demo.start);

Die registrierte Skript-URL darf dabei keinen Platzhalter (wie ~site o.ä. beinhalten), daher verwenden wir das aus der App-Entwicklung bekannte _spPageContextInfo-Objekt, um die aktuelle Site-URL zu ermitteln:

var thisUrl = _spPageContextInfo.siteServerRelativeUrl + "/Style Library/mdstest.js";

Das _spPageContextInfo-Objekt wiederum ist nur vorhanden, wenn wir uns in einer MDS-Navigation befinden. Diesen Fakt nutzen wir, um im Code zwischen MDS- und Nicht-MDS-Navigation zu unterscheiden:

if (typeof _spPageContextInfo != "undefined" && _spPageContextInfo != null) {<br />    // running under MDS<br />    Demo.mdsStart();<br />} else {<br />    // not running under MDS<br />    Demo.start();<br />}

Einleuchtend, oder?

Diese Puzzlesteine zusammenzusetzen wäre nicht möglich gewesen ohne den exzellenten Blogbeitrag von Wictor Wilén: “The correct way to execute JavaScript functions in SharePoint 2013 MDS enabled sites“.

Eine letzte Hürde: Timingprobleme

Prinzipiell haben wir alles richtig gemacht, der Code im letzten Abschnitt würde aber immernoch nicht dazu führen, dass der Webparttitel ausgeblendet wird. Wir haben ein Timingproblem.

Ersetzen wir den Code kurz komplett durch eine einzige Zeile:

alert("JS geladen");

Das Ergebnis nach Neuladen der “Home”-Seite sieht so aus:

jslink-script-timing-problem

Unser Skript wird aktiv, bevor die Seite fertig aufgebaut ist. Und obwohl wir schon den Titel “Documents” sehen, geht folgender Aufruf ins Leere:

document.getElementById("WebPartWPQ2_ChromeTitle");

Das Element existiert noch nicht.

An dieser Stelle folgt die “beliebte” Timer-Lösung: wir verwenden Polling, um festzustellen, wann wir auf das Element zugreifen können.

Mit integriertem Polling sieht der fertige Code nun so aus:

Type.registerNamespace("Demo");<br />Demo = (typeof Demo != "undefined") ?  Demo : {}<br />Demo.hideWebpartTitle = function()<br />{    <br />    var element = document.getElementById("WebPartWPQ2_ChromeTitle");<br />    if (element)<br />    {<br />        element.style.display = "none";<br />    } else<br />    {<br />        Demo.hideWebpartTitleTimed()<br />    }<br />}<br /><br />Demo.hideWebpartTitleTimed = function()<br />{<br />    window.setTimeout(Demo.hideWebpartTitle, 500);<br />}<br /><br />Demo.start = function() {<br />    Demo.hideWebpartTitleTimed();<br />};<br /><br />Demo.mdsStart = function() {<br />    var thisUrl = _spPageContextInfo.siteServerRelativeUrl + "/Style Library/mdstest.js";<br />    Demo.start();<br />    RegisterModuleInit(thisUrl, Demo.start);<br />};<br /><br />if (typeof _spPageContextInfo != "undefined" && _spPageContextInfo != null) {<br />    // running under MDS<br />    Demo.mdsStart();<br />} else {<br />    // not running under MDS<br />    Demo.start();<br />}

Unter Verwendung der Methode hideWebpartTitleTimed wird ein Timer aktiviert, der hideWebpartTitle aufruft, um den Titel auszublenden. Wird dort der Webpart-Titel nicht gefunden, dann wird der Timer erneut aktiviert.

Wir sind am Ziel.

Zusammenfassung

Mit aktivierter Minimal Download Strategy (MDS) müssen bestimmte Regeln beachtet werden, wenn per JSLink an Webparts platzierte Skripte ausgeführt werden sollen. Die obigen Abschnitte zeigen wie es geht.

Es kann zu Timingproblemen kommen, wenn JSLink-Skripte aktiviert werden, bevor benötigte SharePoint-Ressourcen geladen wurden.

Bei der Entwicklung sollte nach der Änderung von per JSLink eingebundenen Skripten der Browsercache geleert werden, damit die Änderungen aktiv werden. Ein einfaches Neu-Laden einer Seite reicht nicht.

Sollten sich Probleme mit der MDS nicht lösen lassen, dann lässt sich die MDS auf Web-Ebene deaktivieren. Dies ist auch per Client Object Model möglich.

Artikel als PDF speichern

Schreiben Sie einen Kommentar

*

Diese Webseite basiert auf Wordpress. © 2014 Communardo Software GmbH / Kleiststraße 10 a / D-01129 Dresden / Fon +49 (0) 351/8 33 82-0 / info@communardo.de