Teil 1: Die Grundlagen

SharePoint-Apps mit AngularJS
Kommentare

Der SharePoint-Server bietet verschiedene Möglichkeiten, eigene Funktionalitäten einzubringen. Um dies zu ermöglichen, besitzt SharePoint ein umfangreiches und offenes Klassenmodell. Wurden in der Vergangenheit eher serverseitige Lösungen realisiert, empfiehlt Microsoft seit SharePoint 2013 die Umsetzung von SharePoint-Apps.

Artikelserie

  • Teil 1: Die Grundlagen
  • Teil 2: Erweiterte Konzepte
  • Teil 3: Realisierung

Das App-Programmiermodell ist seit SharePoint 2013 verfügbar und löst das Sandkastenmodell mehr oder weniger ab. Die Charakteristiken des App-Modells wurden bereits im vorherigen Band erläutert, daher sollen nachfolgend nur die für diesen Artikel wesentlichen Eigenschaften beschrieben werden.

Es gibt zwei Varianten von SharePoint-Apps: entweder mit oder ohne serverseitigen Code. Ein wichtiges Ziel des App-Modells besteht darin, eine Prozessisolation zwischen SharePoint und fremden Erweiterungen zu gewährleisten. Daher benötigen Apps mit serverseitigem Code einen externen bzw. eigenen Server, auf dem der benötigte serverseitige Code ausgeführt werden kann. Dieser Umstand erschwert die Umsetzung und die Bereitstellung von SharePoint-Apps. Einfacher zu realisieren und bereitzustellen sind dagegen reine clientseitige Apps, die keinen serverseitigen Code zur Ausführung benötigen. Diese so genannten SharePoint-betriebenen Apps (SharePoint-hosted Apps) werden direkt vom SharePoint-Server verwaltet und abgerufen. Da hierbei kein serverseitiger Code möglich ist, muss auf JavaScript und das clientseitige Objektmodell (CSOM) zurückgegriffen werden.

CSOM = Client-Side Object Model

Das clientseitige Objektmodell (kurz: CSOM) ist ein wesentlicher Bestandteil des SharePoint-App-Modells, ohne das SharePoint-Apps nicht umsetzbar sind. Es ermöglicht erstmals den Zugriff auf SharePoint von einer anderen Maschine aus bzw. einfach ausgedrückt: Es erlaubt den einfachen „Remote“-basierten API-Zugriff. Bis zur SharePoint-Version 2007 konnte für den API-Zugriff nur das serverseitige Objektmodell verwendet werden, jedoch musste die Anwendung dafür stets auf dem SharePoint-Server ausgeführt werden. Musste dennoch von einer anderen Maschine auf SharePoint-Elemente wie z. B. Listendaten – zugegriffen werden, blieb nur der Weg über die SharePoint-Web-Services. Über die Webdienste können zwar schon Daten abgegriffen werden, jedoch stehen über diesen Weg nicht alle Funktionen des serverseitigen Objektmodells zur Verfügung. Das CSOM schließt nun diese Lücke und stellt (fast) alle Funktionen des serverseitigen Objektmodells bereit. Dabei sind verschiedene CSOM-Bibliotheken zu unterscheiden. Insgesamt stehen in SharePoint die drei folgenden Clientobjektmodelle für verwalteten Code zur Verfügung: .NET, Silverlight und Mobil. Je nach Anwendungstyp muss die passende Bibliothek verwendet werden, da diese auf die speziellen Plattformspezifika zugeschnitten ist. Neben den Bibliotheken für verwalteten Code existiert noch eine spezielle JavaScript-Bibliothek, die auch unter dem Namen JSOM bekannt ist und speziell für die Entwicklung von SharePoint-hosted Apps die erste Wahl ist. Der Vollständigkeit halber sei noch die vorhandene REST-Schnittstelle erwähnt, die eine weitere Zugriffsmöglichkeit – in der Regel sinnvoll für den Zugriff von einer Nicht-Microsoft-Plattform aus – bietet.

Überblick über JSOM

Mithilfe von JSOM ist ein einfacher Zugriff auf SharePoint-Daten und -Funktionen möglich. Da JSOM für die anstehende Realisierung der SharePoint-App mit AngularJS umfassend zum Einsatz kommt, werden nachfolgend die wichtigsten API-Zugriffe sowie die Funktionsweise von JSOM erläutert. Die eigentliche JSOM-JavaScript-Bibliothek ist in der Datei sp.js untergebracht, die sich im Layouts-Ordner von SharePoint befindet. Diese ist zwingend zu referenzieren, wenn über JSOM auf SharePoint zugegriffen werden soll. Auf der SharePoint-Seite nimmt ein Endpoint die API-Aufrufe entgegen und leitet diese intern an SharePoint weiter. Abbildung 1 verdeutlicht die Architektur: Wie hier zu erkennen, nimmt der WCF Endpoint client.svc die Anfragen entgegen. Die JavaScript-, Silverlight- und.NET-Bibliotheken interagieren über einen Proxy mit SharePoint. Der Proxy nimmt die Anfragen entgegen und veranlasst die Ausführung. Die REST-(ODATA-)Schnittstelle – in der Abbildung nicht dargestellt – greift über den gleichen Endpoint auf die SharePoint-Daten zu.

Abb. 1: Struktur des clientseitigen Objektmodells, Quelle: http://msdn.microsoft.com/en-us/library/office/jj163228(v=office.15).aspx

Abb. 1: Struktur des clientseitigen Objektmodells, Quelle: http://msdn.microsoft.com/en-us/library/office/jj163228(v=office.15).aspx

Auf der Seite des Clients stellt ein Kontextobjekt das Gegenstück zum serverseitigen Endpunkt dar. Der clientseitige Kontext arbeitet stapelorientiert, d. h. es können mehrere Anfragen/Operationen auf ihm ausgeführt werden, die zunächst nicht an SharePoint weitergegeben werden. Erst durch bestimmte API-Aufrufe sendet der Kontext alle anstehenden Operationen an SharePoint. Auf der Serverseite werden die gesammelten Anfragen ausgeführt und das gesamte Ausführungsergebnis einmalig an den Client zurückgesendet. Durch diese Arbeitsweise wird der Netzwerkverkehr minimiert und eine bessere Performance der Anwendung erreicht. Im Zusammenhang mit den clientseitigen API-Zugriffen – sei es über eine CSOM-Bibliothek oder auch über REST – kommt häufig die Frage nach der Sicherheit auf. Hier sei erwähnt, dass auch über alle anderen Zugriffswege – also an der SharePoint-Oberfläche vorbei – die aktuellen Berechtigungen des Benutzers zum Tragen kommen. Eine Übersicht über das JSOM-API ist hier zu finden.

Verwendung von JSOM

Zu den typischen und am häufigsten benötigten API-Zugriffen zählen Listenoperationen. Viele eigene SharePoint-Erweiterungen nutzen zur Datenablage benutzerdefinierte SharePoint-Listen. Auch über JSOM werden natürlich alle wichtigen Listenoperationen wie Lesen, Schreiben, Löschen und Anfügen (also alle CRUD-Operationen) unterstützt. Listing 1 zeigt, wie einer bestehenden Aufgabenliste ein neuer Eintrag hinzugefügt werden kann. Zur besseren Übersicht wurde das Beispiel als reine HTML-Seite mit lediglich den wichtigsten Bestandteilen umgesetzt. Um die JSOM-Funktionen nutzen zu können, müssen der Seite zunächst die folgenden Skriptreferenzen hinzugefügt werden:

  • MicrosoftAjax.js
  • sp.runtime.js
  • sp.js

Diese sind zwingend erforderlich, ansonsten kommt es zu Ausführungs- bzw. Ladefehlern. Die JavaScript-Funktion addToTaskList beinhaltet den gesamten Code, um einen neuen Listeneintrag zu erstellen. Wie bereits anhand der Funktionsbeschreibung des CSOM dargestellt, werden alle JSOM-Operationen auf einem Kontextobjekt ausgeführt. Aus diesem Grund wird im ersten Schritt die Variable clientContext initialisiert. Als Kontext wird hier das aktuelle Web verwendet. Anschließend wird die Variable oList mit der gewünschten Referenz auf die Zielliste ausgestattet. Ein neuer Eintrag wird mithilfe eines Objekts vom Typ ListItemCreationInformation erstellt. Steht das Objekt bereit, kann über oList.addItem und die Übergabe des Objekts ein neuer Eintrag erstellt werden. Das neu abgerufene Listenobjekt muss anschließend nur noch mit den gewünschten Werten befüllt werden. Nachdem die Änderungen über den update-Methodenaufruf bestätigt wurden, werden alle offenen Änderungen des Kontexts über executeQueryAsync zum SharePoint-Server gesendet. Dieser Funktion werden zwei Delegates übergeben. Der erste wird im Erfolgsfall, der zweite im Fehlerfall aufgerufen.

http://www.w3.org/1999/xhtml">JSOM-Examples<script src="//ajax.aspnetcdn.com/ajax/ 4.0/1/MicrosoftAjax.js" type="text/javascript"></script><script src="/_layouts/15/sp.runtime.js" type="text/javascript"></script><script src="/_layouts/15/sp.js" type="text/javascript"></script><script type="text/javascript">// <![CDATA[
      var clientContext;
      function addToTaskList() {
        clientContext = SP.ClientContext.get_current();

        var oList = clientContext.get_web().get_lists().getByTitle("Aufgaben");
        var newTaskItem = new SP.ListItemCreationInformation();
        this.newItem = oList.addItem(newTaskItem);
        newItem.set_item("Title", "Eine neue Aufgabe über JSOM");
        newItem.set_item("Body", "Beschreibung der Aufgabe");
        newItem.update();
        clientContext.load(newItem);      
        clientContext.executeQueryAsync(
          function () { 
            alert("Eintrag wurde hinzugefügt."); }, 
          function () { 
            alert("Eintrag konnte nicht hinzugefügt werden.")});
      }
    
// ]]></script><input type="button" value="Call via JSOM" />

Für alle weiteren Beispiele sei an dieser Stelle auf die ausführliche MSDN-Dokumentation verwiesen, die eine gute Übersicht über die Standardoperationen gibt. Neben den dort beschriebenen Operationen können aber auch weitere SharePoint-Funktionen über das JSOM genutzt werden. Für die später umzusetzende Beispielanwendung werden erweiterte Benutzerprofildaten benötigt. SharePoint 2013 bietet dazu den Dienst „User Profile Service“ an, der zunächst die Aufgabe hat, Benutzerinformationen aus anderen Verzeichnisdiensten wie z. B. Active Directory nach SharePoint zu übernehmen. Wie viele anderer SharePoint-Dienste besitzt auch dieser eine offene Schnittstelle und kann somit in eigenen Anwendungen verwendet werden. Der Dienst ermöglicht – wie der Name schon vermuten lässt – die Verwaltung und das Abrufen von erweiterten Benutzerdaten. Listing 2 demonstriert, wie dieser Dienst über das JSOM verwendet werden kann. Damit die Funktion getUserData ausgeführt werden kann, muss die HTML-Seite wiederum alle JavaScript-Referenzen aus Listing 1 besitzen. Damit die speziellen Benutzerprofilfunktionen bereitstehen, muss zusätzlich noch die folgende Bibliothek referenziert werden: /_layouts/15/SP.UserProfiles.js. Die Verwendungsweise des API ähnelt dann wieder der Vorgehensweise im Beispiel aus Listing 1. Zunächst muss wieder ein SharePoint- Kontext abgerufen werden. Danach wird eine Instanz vom Typ PeopleManager erstellt. Über diesen Manager können anschließend Benutzerprofileigenschaften über die Methode getPropertiesFor abgerufen werden. Der Methode muss lediglich der Accountname des abzufragenden Benutzers übergeben werden. Wie anhand dieser beiden kleinen Beispiele deutlich wurde, bietet JSOM einen einfachen und strukturierten Weg zum Zugriff auf SharePoint-Daten und -Funktionen.

function getUserData(targetUser) {
  var clientContext = new SP.ClientContext.get_current();
  var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);
  personProperties = peopleManager.getPropertiesFor(targetUser);
  clientContext.load(personProperties);
  clientContext.executeQueryAsync(onRequestSuccess, onRequestFail);
}
function onRequestSuccess() {
  alert("Anzeigename des Benutzers: " + personProperties.get_displayName());
}
function onRequestFail(sender, args) {
  alert("Fehler: " + args.get_message());
}

AngularJS – eine Übersicht

Die geplante App wird als SharePoint-gehostete App realisiert, d. h., clientseitig muss die gesamte App-Logik mittels JavaScript realisiert werden. Auch wenn JavaScript (fast) alle Konzepte einer objektorientierten Sprache anbietet, ist die Realisierung einer Anwendungsarchitektur allein mit JavaScript schwierig. Viele JavaScript-Programme erinnern mehr an eine Script-Lösung und erschweren somit die Wartung und den zukünftigen Ausbau. Um dennoch eine strukturierte Anwendung basierend auf JavaScript umsetzen zu können und nicht selbst in die Tiefen der nativen JavaScript-Implementierung absteigen zu müssen, stehen unterstützende Bibliotheken zu Verfügung. Eine davon ist die von Google initiierte Open-Source- Bibliothek AngularJS. Auch wenn sie schon seit 2009 existiert, ist ihr Bekanntheitsgrad erst in den letzten Jahren extrem angestiegen. AngularJS betitelt sich selbst als das „Superheroic JavaScript MVW Framework“ – mit dieser Aussage verbunden steigen die Erwartungen an das Framework natürlich entsprechend an. Schaut man sich den Funktionsumfang der Bibliothek an, ist diese selbstbewusste Aussage aber gar nicht falsch. Zu den wichtigsten Eigenschaften von AngularJS zählen: •    Vollständig deklarativ, wie auch XAML •    Filter (vgl. WPF IValueConverter) •    Control (entsprechen Direktiven) •    Zwei-Wege-Datenbindung •    Trennung zwischen Layout und Frontend-Code •    Dependency Injection •    Unit Tests (QUnit, Jasmine) und Protractor •    Geeignet für große Projekte und mehrere aktive Entwickler AngularJS strukturiert eine JavaScript-Anwendung gemäß dem bekannten MVC-Muster. Die in diesem Muster verfügbaren Modelldaten können per deklarativer Bindung an die Oberfläche gebunden werden. Das Vorgehen ist mit einer WPF-basierten Anwendung vergleichbar und ermöglicht so die Trennung zwischen Layout und Frontend-Code. Die Datenbindung ist dabei bidirektional, sodass Datenänderungen, die beispielsweise über die Oberfläche erfolgt sind, automatisch in das Modell übernommen werden. Über so genannte Direktiven (Directives) können benutzerdefinierte HTML-Elemente und -Attribute erstellt werden. Eigene Direktiven erlauben die einfache Umsetzung von wiederverwendbaren Komponenten. Ebenfalls analog zur WPF-Schnittstelle IValueConverter ermöglicht ein AngularJS-Filter die Aufbereitung eines Werts für die Präsentation auf der Oberfläche. AngularJS ist modular aufgebaut und benötigte Funktionen werden per Dependency Injection zur Verfügung gestellt. Die Modularisierung findet sich ebenfalls in den einzelnen AngularJS-JavaScript-Dateien wieder. So müssen nur die JS-Dateien referenziert werden, deren enthaltene Funktionalität tatsächlich benötigt wird. Dies spart das Laden von nicht benötigten Script-Inhalten ein. Weiterhin unterstützt AngularJS die Verwendung von Units Tests wie z. B. Jasmine, um automatisierte Prüfungen des Codes zu ermöglichen. Auch unsere geplante SharePoint-App soll mithilfe von AngularJS umgesetzt werden. Daher werden nachfolgend die wichtigsten Implementierungseigenschaften der Bibliothek anhand von Beispielen erläutert, die bei der Umsetzung der App schließlich zum Einsatz kommen.

Angular-App-Struktur und die Zwei-Wege-Datenbindung

Der wesentliche Vorteil bei der Verwendung von AngularJS ist der Datenbindungsmechanismus. Wird kein Framework eingesetzt, sind die folgenden Schritte, die jedem JavaScript-Entwickler bestens vertraut sein dürften, manuell durchzuführen: 1. Daten werden dynamisch über einen asynchronen Datenabruf geladen. 2. Die geladenen Daten werden über DOM-Manipulation den Eingabefeldern der Oberfläche zugewiesen. 3. Der Benutzer aktualisiert die Daten. 4. Beim Speichern müssen die geänderten Daten wieder in das geladene Objekt zurückübertragen werden. Dies erfolgt wiederum über direkte manuelle DOM-Zugriffe. AngularJS vereinfacht diese Vorgänge durch den Datenbindungsmechanismus erheblich. Im Grunde fallen dabei alle manuellen Schritte weg. Listing 3 zeigt dazu ein einfaches Beispiel und verdeutlicht den Aufbau eines AngularJS-Programms. Der zunächst wichtigste Punkt ist die Einbindung der AngularJS-Bibliothek. Diese kann entweder zunächst heruntergeladen und lokal referenziert werden oder es wird, wie in unserem Beispiel, ein Content Delivery Network (CDN) genutzt. Ist die Bibliothek eingebunden, muss das AngularJS-Framework initialisiert werden, wie viele andere Frameworks auch. Dies geschieht über das spezielle Attribut ng-app, das meist auf oberster Dokumentenebene (hml oder body) zu finden ist. Ohne dieses Attribut wird AngularJS nicht für das Dokument ausgeführt. Somit sind die wichtigsten Punkte bereits umgesetzt. Unser Beispiel definiert dann einen einfachen Controller namens AppController, der ein simples Datenobjekt mit drei Eigenschaften enthält. In der Praxis werden diese Daten typischerweise über einen Dienst clientseitig asynchron geladen. Das definierte Datenobjekt wird dann der Scope-Eigenschaft CurrentItem zugewiesen. Der $scope stellt im AngularJS-Kontext das Modell dar. Dies wird deutlich, wenn man im Vergleich dazu die untere HTML-Definition betrachtet. Die Eingabefelder (Input Tags) werden über das Attribut ng-model an die zugehörigen Datenobjekteigenschaften gebunden. Das Gleiche geschieht im unteren Bereich, wobei die Daten lediglich in einen p-Tag ausgegeben werden. Führt man dieses Beispiel aus und trägt Daten in die Eingabefelder ein, werden die Änderungen sofort in den zugehörigen p-Tags ausgegeben. Die Änderungen werden also direkt bei der Eingabe in das Datenobjekt übertragen. Wie hieran sehr gut zu erkennen ist, sind keinerlei direkten DOM-Zugriffe notwendig. Das gezeigte Prinzip setzt sich stringent in AngularJS fort und macht daher im Grunde alle direkten DOM-Zugriffe obsolet. Auch dies ist mit dem WPF-(XAML)-Konzept vergleichbar. Auch bei solchen Anwendungstypen sollte nie direkt auf die Oberfläche zugegriffen werden.

http://www.w3.org/1999/xhtml" ng-app><script class="elf-external elf-icon" src="<a href=">// <![CDATA[
https://ajax.googleapis.com/ajax/libs/angularjs/</a> 1.0.6/angular.min.js">
// ]]></script><script type="text/javascript">// <![CDATA[
      function AppController($scope) {
        var dataObject = {
          FirstName: "Angular",
          LastName: "JavaScript",
          Street: "Google Road 1"
        }
        $scope.CurrentItem = dataObject;
      }
    
// ]]></script>Vorname: <input type="text" /> Nachname: <input type="text" /> Strasse: <input type="text" /> Vorname {{CurrentItem.FirstName}} Nachname {{CurrentItem.LastName}} Strasse {{CurrentItem.Street}}

Übersicht über eine AngularJS-Anwendung

Nachdem nun im ersten Beispiel die Funktionsweise von AngularJS dargestellt wurde, gibt Abbildung 2 einen grafischen Überblick über die einzelnen Komponenten. Das Beispiel aus Listing 3 wurde hier auf die Frameworkkomponenten Model-View-Controller projiziert. Im linken oberen Bereich ist die View abgebildet. Diese besteht im AngularJS-Kontext immer aus einem HTML-Template. Dieses enthält typischerweise Datenbindungen, die, abhängig vom HTML-Tag, entweder über geschweifte Klammern ({{AUSDRUCK}}) oder über das Attribut ng-model eingeleitet werden. Das Model selbst, in der Abbildung unten links zu sehen, besteht im Wesentlichen aus einem JavaScript-Objekt. Typischerweise wird dieses über einen Webdienst asynchron geladen. Der Controller selbst ist für die Verwaltung des Models zuständig. Wie in der Fortsetzung dieses Artikels deutlich werden soll, übernimmt der Controller auch weitere Aufgaben wie etwa das Laden und das Speichern von Daten.

Abb. 2: Aufteilung einer AngularJS-Anwendung

Abb. 2: Aufteilung einer AngularJS-Anwendung

Ausblick

Im ersten Teil dieser dreiteiligen Serie wurden die wesentlichen Grundlagen erläutert, die für die zu realisierende SharePoint-App benötigt werden. Wie demonstriert wurde, bietet die SharePoint-JSOM-Bibliothek ein umfassendes API an, um clientseitig aus JavaScript heraus auf SharePoint zuzugreifen. Dabei ist der Zugriff nicht nur auf Daten beschränkt, sondern fast alle Funktionalitäten können über das API verwendet werden. Die zweite wichtige Bibliothek ist AngularJS. Hier wurde anhand eines ersten Beispiels gezeigt, wie eine AngularJS-Anwendung aufgebaut ist und wie die einzelnen M-V-C-Komponenten zusammenhängen und interagieren. Im zweiten Teil dieser Serie werden erweiterte Konzepte erläutert werden, bevor im dritten und letzten Teil schließlich die gesamte SharePoint-App realisiert wird.

Aufmacherbild: woman and man hands with smartphone and tablet pc von Shutterstock / Urheberrecht: Syda Productions

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -