Communardo Software GmbH, Kleiststraße 10 a, D-01129 Dresden
0800 1 255 255

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

Teil 1: JSLink: you've got the whole SharePoint in your hands
Teil 2: JSLink: was man sonst noch wis­sen sollte
Teil 3: JSLink – Problemfall Minimal Download Strategy (MDS) (die­ser Artikel)

SharePoint 2013 bie­tet mit JSLink die Möglichkeit, die Bedienoberfläche für den Anwender ver­gleichs­weise ein­fach anzu­pas­sen. Dabei kommt kommt JavaScript zum Einsatz, wel­ches die Oberfläche cli­ent­sei­tig verändert.

Im Zusammenhang mit der Minimal Download Strategy (MDS) kann es pas­sie­ren, dass per JSLink ein­ge­bun­dene Skripte nicht aus­ge­führt wer­den. Die MDS ist eine – eben­falls neue – Technik, um die mit dem Server aus­ge­tauschte Datenmenge zu reduzieren.

Der Beitrag zeigt anhand eines ein­fa­chen JSLink-Anwendungsfalls, wel­che Fallen es im Zusammenspiel mit der MDS gibt und wie Skriptcode aus­sieht, der die­sen aus dem Weg geht.

Was ist die Minimal Download Strategy (MDS)?

Mit der neu ein­ge­führ­ten MDS redu­ziert SharePoint 2013 die Menge der bei einer Seitennavigation zwi­schen Client und Server aus­ge­tausch­ten Daten. Seiteninhalte, die sich nicht ändern, müs­sen auch nicht neu über­tra­gen werden.

Auf dem Server wird die Differenz (Delta) zwi­schen der aktu­ell ange­zeig­ten Seite und einer neu ange­for­der­ten Seite berech­net. Nur die­ses Delta wird an den Client geschickt, der damit die alte Seite zur neuen Seite umformt. Und das alles per JavaScript.

Für wel­che Sites das MDS-Feature stan­dard­mä­ßig akti­viert ist und wel­che Magie bei der Seitennavigation im Detail pas­siert lässt sich auf den fol­gen­den Seiten nachlesen:

Woran erkenne ich eine MDS-Navigation?

Die MDS ist stan­dard­mä­ßig in Team Sites, Blogs und eini­gen wei­te­ren Site Templates akti­viert. In Publishing Sites ist sie deak­ti­viert. Darüber hin­aus kann SharePoint in Einzelfällen ent­schei­den, die MDS zu deaktivieren.

Woran lässt sich erken­nen, ob eine Seitennavigation mit akti­vier­ter MDS durch­ge­führt wurde? An der URL.

Hier die URL einer Team Site-Startseite mit akti­ver MDS:

mds-url

Die Seite start.aspx dient als Container, der alle Basiselemente einer Seite ent­hält. Sie lädt außer­dem die Skripte, die das vom Server emp­fan­gene Delta ver­ar­bei­ten und die Zielseite zusammenbauen.

Hier dage­gen die URL einer Team Site-Startseite ohne MDS:

non-mds-url

Die URL sieht "nor­mal" aus.

(Sollten Sie im Browser einen Redirect von einer "MDS-URL" auf eine "Nicht-MDS-URL" beob­ach­ten, dann hat SharePoint in den failover-Modus geschal­tet und die MDS-Navigation abge­bro­chen. Das kann bspw. durch Skriptfehler in JSLink-JavaScript-Dateien ver­ur­sacht werden.)

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

Ohne MDS ein Erfolg: Anpassung einer Listenansicht per JSLink

Unser Test-Anwendungsfall: Wir ent­fer­nen die Überschrift eines Listenwebparts per JavaScript, wel­ches per JSLink an den Webpart gebun­den wird.

Im Beitrag "JSLink: You've got the whole SharePoint in your hands" wurde bereits gezeigt, wel­che Macht JSLink für die Anpassung der Oberfläche besitzt.

In einer neuen Team Site dient der "Documents"-Webpart als Versuchsobjekt. Dieser befin­det sich auf der Startseite der Team Site:

team-site-documents-webpart

Das Ziel: die Überschrift "Documents" ent­fer­nen. Dazu benö­ti­gen wir eine JavaScript-Datei, die den pas­sen­den Code enthält:

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

Das HTML-Element mit der ID "WebPartWPQ2_ChromeTitle" ent­hält den Titel, also holen wir uns die­ses Element und blen­den es aus. Die Funktion hideWebpartTitle plat­zie­ren wir dabei im Namespace Demo, um den glo­ba­len Namensraum nicht zu verunreinigen.

Die Datei spei­chern wir als "mdstest.js" und laden Sie in die Style Library hoch:

mds-js-file-style-library

Anschließend bin­den wir die Datei per JSLink an den XsltListViewWebpart, der für die Darstellung der Documents-Liste ver­ant­wort­lich ist.

JSLink lässt sich in den Webparteigenschaften konfigurieren:

mds-xsltlistviewwebpart-jslink

Wir ver­wen­den den Platzhalter ~site um den Pfad zu unse­rer .js-Datei rela­tiv zum Web zu adres­sie­ren. (Weitere Platzhalter fin­den Sie in die­sem Beitrag.)

Nach dem Speichern des Webparts und der Seite laden wir diese mit F5 neu. Und wir sehen den gewünsch­ten Effekt, der Titel ist aus­ge­blen­det:

mds-webpart-title-hidden-with-jslink

Mit MDS funktioniert nichts mehr (vorerst)

Wir lösen eine MDS-Navigation aus und stel­len fest: unsere per JSLink an den Webpart gebun­dene JS-Datei wird nicht mehr aus­ge­führt. Der Webparttitel bleibt also sichtbar.

Die MDS-Navigation lässt sich wie folgt aus­lö­sen: im Schnellstartmenü wäh­len wir einen belie­bi­gen ande­ren Menüpunkt und anschlie­ßend wie­der den Ursprungs-Menüpunkt "Home".

mds-navigation

Schauen wir uns den "Documents"-Webpart jetzt an, dann sehen wir, dass der Titel noch vor­han­den ist. Unser Script wurde also nicht ausgeführt:

team-site-documents-webpart-title

Laden wir nun die Seite neu, ver­schwin­det der Webparttitel wieder:

 

 mds-f5-jslink-fix

Dieses Spiel lässt sich belie­big 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 beinhal­tet ein Opt-In-Modell für Navigationsereignisse. Skripte, die bei einer Navigation aus­ge­führt wer­den sol­len, müs­sen regis­triert wer­den. Darüber hin­aus ver­wen­det die MDS einen Garbage Collector, der den glo­ba­len Namensraum rei­nigt. Werden Objekte im glo­ba­len Namensraum plat­ziert (wie unser Demo-Objekt), dann wer­den diese u.U. ent­fernt. Um dem zu ent­ge­hen, müs­sen Objekte als Namensraum regis­triert weden.

Wir pas­sen unser Skript die­sen Regeln an und das Ergebnis sieht so aus:

Type.registerNamespace("Demo");
Demo = (typeof Demo != "undefined") ?  Demo : {}
Demo.hideWebpartTitle = function()
{    
    document.getElementById("WebPartWPQ2_ChromeTitle").style.display = "none";
}

Demo.start = function() {
    Demo.hideWebpartTitle();
};

Demo.mdsStart = function() {
    var thisUrl = _spPageContextInfo.siteServerRelativeUrl + "/Style Library/mdstest.js";
    Demo.start();
    RegisterModuleInit(thisUrl, Demo.start);
};

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

Die Registrierung unse­res Namensraumes "Demo" schützt ihn vor dem Garbage Collector:

 Type.registerNamespace("Demo");

Die Registrierung unse­res Skripts mit­tels RegisterModuleInit ist not­wen­dig, damit die­ses auch bei MDS-Navigation auf­ge­ru­fen wird:

RegisterModuleInit(thisUrl, Demo.start);

Die regis­trierte Skript-URL darf dabei kei­nen Platzhalter (wie ~site o.ä. beinhal­ten), daher ver­wen­den wir das aus der App-Entwicklung bekannte _spPageContextInfo-Objekt, um die aktu­elle Site-URL zu ermitteln:

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

Das _spPageContextInfo-Objekt wie­derum ist nur vor­han­den, wenn wir uns in einer MDS-Navigation befin­den. Diesen Fakt nut­zen wir, um im Code zwi­schen MDS- und Nicht-MDS-Navigation zu unterscheiden:

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

Einleuchtend, oder?

Diese Puzzlesteine zusam­men­zu­set­zen wäre nicht mög­lich gewe­sen ohne den exzel­len­ten Blogbeitrag von Wictor Wilén: "The cor­rect way to exe­cute JavaScript func­tions in SharePoint 2013 MDS enab­led sites".

Eine letzte Hürde: Timingprobleme

Prinzipiell haben wir alles rich­tig gemacht, der Code im letz­ten Abschnitt würde aber immer­noch nicht dazu füh­ren, dass der Webparttitel aus­ge­blen­det wird. Wir haben ein Timingproblem.

Ersetzen wir den Code kurz kom­plett durch eine ein­zige 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 fer­tig auf­ge­baut ist. Und obwohl wir schon den Titel "Documents" sehen, geht fol­gen­der Aufruf ins Leere:

document.getElementById("WebPartWPQ2_ChromeTitle");

Das Element exis­tiert noch nicht.

An die­ser Stelle folgt die "beliebte" Timer-Lösung: wir ver­wen­den Polling, um fest­zu­stel­len, wann wir auf das Element zugrei­fen können.

Mit inte­grier­tem Polling sieht der fer­tige Code nun so aus:

Type.registerNamespace("Demo");
Demo = (typeof Demo != "undefined") ?  Demo : {}
Demo.hideWebpartTitle = function()
{    
    var element = document.getElementById("WebPartWPQ2_ChromeTitle");
    if (element)
    {
        element.style.display = "none";
    } else
    {
        Demo.hideWebpartTitleTimed()
    }
}

Demo.hideWebpartTitleTimed = function()
{
    window.setTimeout(Demo.hideWebpartTitle, 500);
}

Demo.start = function() {
    Demo.hideWebpartTitleTimed();
};

Demo.mdsStart = function() {
    var thisUrl = _spPageContextInfo.siteServerRelativeUrl + "/Style Library/mdstest.js";
    Demo.start();
    RegisterModuleInit(thisUrl, Demo.start);
};

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

Unter Verwendung der Methode hideWebpartTitleTimed wird ein Timer akti­viert, der hideWebpartTitle auf­ruft, um den Titel aus­zu­blen­den. Wird dort der Webpart-Titel nicht gefun­den, dann wird der Timer erneut aktiviert.

Wir sind am Ziel.

Zusammenfassung

Mit akti­vier­ter Minimal Download Strategy (MDS) müs­sen bestimmte Regeln beach­tet wer­den, wenn per JSLink an Webparts plat­zierte Skripte aus­ge­führt wer­den sol­len. Die obi­gen Abschnitte zei­gen wie es geht.

Es kann zu Timingproblemen kom­men, wenn JSLink-Skripte akti­viert wer­den, bevor benö­tigte SharePoint-Ressourcen gela­den wurden.

Bei der Entwicklung sollte nach der Änderung von per JSLink ein­ge­bun­de­nen Skripten der Browsercache geleert wer­den, damit die Änderungen aktiv wer­den. Ein ein­fa­ches Neu-Laden einer Seite reicht nicht.

Sollten sich Probleme mit der MDS nicht lösen las­sen, dann lässt sich die MDS auf Web-Ebene deak­ti­vie­ren. Dies ist auch per Client Object Model möglich.

Related Posts

Pin It on Pinterest