Promise – Versprechen für TypeScript

Wenn immer ich etwas mit SharePoint programmiere versuche ich es in TypeScript zu schreiben. Mir gefällt das Konzept von Klassen und Vererbung und das möchte ich auch in der JavaScript Welt nicht missen.

Was jedoch bleibt ist die Asynchronität des Client Objekt Models. Die vielen Callback-Funktionen machen den Code doch recht unübersichtlich und das ist auch mit Klassen nicht gut zu lösen.

Vor kurzem bin ich über das Promise Framework für Typescript gestoßen. Es ist leicht über NuGet zu installieren (https://www.nuget.org/packages/Promise.TypeScript/1.0.0-rc)

Die Idee ist, dass eine Funktion nicht den Rückgabewert zurückliefert sondern ein “Versprechen” einen bestimmten Wert für einen Datentyp zu einem späteren Zeitpunkt zur Verfügung zu stellen.

In meinem BSP habe ich eine Klasse angelegt um Listen im SharePoint Host Web anzulegen. Die gesamte Funktionalität ist in der Klasse gekapselt.

Der Code der nun von auszuführen ist um eine Liste anzulegen sieht so aus:

1 function ListeAnlegen() { 2 var ctl = new ListHandler(); 3 var cth = new ContentTypeHandler(); 4 var name = $('#txtCTname').val(); 5 6 showWarten(); 7 cth.GetWebContentTypeByName("ppStandorte"). 8 done(ct => { 9 ctl.AddListToWeb(SPContextHelper.HostCTX().get_web(), name, ct) 10 .done((liste: SP.List) => { }) 11 .fail(err => { alert(err.message) }) 12 .always(() => { hideWarten() }); 13 }); 14 }

 

Den Zugriff auf das Hostweb habe ich ebenfalls gekapselt. Die Methode HostCTXC() stellt einen AppSiteContext ins Hostweb zur Verfügung.

Die Methode AddListToWeb erwartet das Web, einen Listennamen und einen Contenttype der zur Liste hinzugefügt werden soll. Den Aufruf sieht man in Zeile 9.

Danach folgt gleich die Verwendung von Promise. in Zeile 10 kommt ein Eventhandler für Done und wird aufgerufen, sobald im dem Promise die Daten bereitstehen.

Sollte es zu einem Fehler kommen wird in Zeile 11 eine Eventhandler für Fail hinterlegt und zuletzt kann mit .always ein Eventhandler angelegt werden, der immer aufgerufen wird.

Das macht den Code deutlich lesbarer und übersichtlicher. Jetzt stellt sich nur noch die Frage wie ist die Methode AddListToWeb zu implementieren ist:

1 class ListHandler { 2 /// Legt eine Liste an und setzt den CT in die List 3 AddListToWeb(web: SP.Web, ListName: string, ContentType: SP.ContentType) : P.Promise<SP.List> { 4 var ret: P.Deferred<SP.List> = P.defer<SP.List>(); 5 6 this.Exists(ListName).done((erg) => { 7 if (erg == true) 8 { 9 alert('exits'); 10 ret.resolve(null); 11 } 12 else { 13 var lci: SP.ListCreationInformation = new SP.ListCreationInformation(); 14 lci.set_title(ListName); 15 lci.set_templateType(SP.ListTemplateType.genericList); 16 lci.set_quickLaunchOption(SP.QuickLaunchOptions.on); 17 var liste: SP.List = web.get_lists().add(lci); 18 19 liste.get_contentTypes().addExistingContentType(ContentType); 20 var ctx: SP.AppContextSite = SPContextHelper.HostCTX(); 21 22 SPContextHelper.AppCTX().executeQueryAsync( 23 () => { 24 ret.resolve(liste); 25 }, 26 () => { 27 ret.reject({message:'Liste existiert bereits'}); 28 }); 29 } 30 }); 31 32 return ret.promise(); 33 } 34 }

Zunächst sieht man, dass die Methode ein Objekt vom Typ P.Promise<> zurückgibt. Hier werden Generics verwendet, daher definiert meine Methode dass der Datentype der im Promise enthalten sein wird ein Objekt vom Typ SP.List sein wird.

In Zeile 4 wird das leere Rückgabe-Element definiert. Dieses ist vom Typ Deferred<SP.List>. In Zeile 32 wird dann das entsprechende Promise Objekt zurückgegeben. Nun hat die Methode auch einen korrekten Rückgabewert. Nur wird dieses Objekt noch keinen Inhalt haben. Innerhalb der Methode wird mit dem CSOM die Liste angelegt und in Zeile 24, wird mit der Methode res.resolve() ein Datenobjekt in das Promise geladen. Dieses steht dann im Aufruf der .Done() Methode zur Verfügung. (vgl Zeile 10 vom ersten Listing)

Mit der Methode .Reject kann ein Fehler gemeldet werden. Beim Aufruf wird die Methode .fail() ausgeführt. Im Reject kann noch ein weiteres Objekt übergeben werden welches beim Fail ausgelesen werden kann (Zeile 11 im ersten Listing)

Diese Code ist nur ein kleiner Ausschnitt eines größeren Projektes um das Remote Provisioning zu demonstrieren. Das gesamte Projekt mit ausführlichen Erklärungen zeige ich auf der SharePoint konferenz am 17 und 18. Juni in Wien.

Kommentare sind geschlossen