Single Page Applications mit AngularJS, Teil 1: Erste Schritte

Werkzeuge  –  4 Kommentare

Datenbindung und das Einarbeiten externer Dienste sind nur zwei der Aufgaben, um die sich Entwickler von JavaScript-Apps kümmern müssen. Googles Framework AngularJS soll sie beim Erstellen von Applikationen unterstützen, die nur aus einer Seite bestehen.

Das Erstellen von Anwendungen in JavaScript gestaltet sich anspruchsvoll: Der Entwickler muss sich um das Binden von Daten, das Aufrufen von Services und das Validieren von Eingaben kümmern. Der Quellcode, der dabei entsteht, soll darüber hinaus auch überschau-, wart- und testbar sein. All das ist mit JavaScript zwar möglich, fordert dem Entwickler aber viel Disziplin ab und geht mit dem Schreiben großer Mengen ähnlicher Codestrecken einher.

JavaScript-Frameworks versprechen dafür Abhilfe. Eines davon ist AngularJS, das aus der Feder von Google stammt. Es zeichnet sich dadurch aus, dass es viele Aspekte moderner JavaScript-Anwendungen unterstützt und dabei die Kriterien Wartbarkeit und Testbarkeit in den Vordergrund stellt.

Artikelserie zu AngularJS

Zur Einführung in AngularJS beschreibt diese Artikelserie die Umsetzung einer einfachen Single Page Application (SPA). Sie soll dem Anwender die Möglichkeit geben, unter Verwendung eines mit JSON arbeitenden HTTP-Services Flüge zu buchen. Abbildung 1 veranschaulicht die vier Bereiche der SPA: Unter "Passagier" kann der Anwender nach einem Passagier suchen, indem er entweder dessen Nachnamen oder Nummer erfasst. Den gewünschten Passagier kann er anschließend auswählen. Unter "Flug" sucht der Anwender analog dazu einen Flug und wählt ihn aus. Filtern kann er entweder nach der Flugnummer oder nach dem Abflugs- und Zielflughafen. Im Bereich "Buchen" besteht die Möglichkeit, eine Buchung für den gewählten Passagier und Flug zu erstellen und unter "Meine Buchungen" kann der Anwender auf die von ihm gebuchten Flüge zugreifen.

Suchen und Auswählen eines Passagiers in der Beispielanwendung (Abb. 1)


AngularJS strukturiert Anwendungen anhand von Modulen. Ähnlich wie Namespaces unter .NET kapselt ein Modul wiederverwendbare Programmteile und Konfigurationsinformationen. Zu Ersteren zählen Controller im Sinne des Musters MVC (Model View Controler). Controller haben in AngularJS die Aufgabe, Models bereitzustellen. Letztere lassen sich anschließend von einer View visualisieren.

Der folgende Codeausschnitt zeigt, wie der Entwickler ein Modul mit einem Controller bereitstellen kann.

var app = angular.module("Flug", []);


app.controller("FlugBuchenCtrl", function ($scope, $http, $q) {
$scope.vm = new FlugBuchenVM($scope, $http, $q);
});

Dazu nutzt er die Funktion module des globalen Objektes angular, das die von AngularJS bereitgestellten Konstrukte enthält. Damit die Funktion ein Modul einrichtet, übergibt der Entwickler den Namen des neuen Moduls und ein Array mit jenen Modulen, die in das neue Modul zu importieren sind. Durch diese Möglichkeit können Entwickler wiederkehrende Aufgaben auslagern.

Da im betrachteten Beispiel kein Modul (explizit) zu importieren ist, übergibt das betrachtete Beispiel lediglich ein leeres Array. Übergibt der Entwickler neben dem Namen des Moduls keine weiteren Argumente, erzeugt module kein neues Modul, sondern liefert ein bestehendes mit dem angegebenen Namen zurück – sofern ein solches existiert. (Genaugenommen wird in jedes neue Modul das Modul ng importiert, das die von AngularJS bereitgestellten Funktionen enthält. Das gilt auch, wenn ng, wie im gezeigten Beispiel, nicht explizit angegeben wird.)

Die Funktion module retourniert ein Objekt, welches das jeweilige Modul beschreibt. Das Beispiel nutzt die Funktion controller des Objekts, um einen neuen Controller einzurichten. Der erste Parameter ist der Name des Moduls. Beim zweiten handelt es sich um eine Funktion, die sich zum Ermitteln von Views nutzen lässt. Sie kann mit einer Action-Methode bei ASP.NET MVC verglichen werden.

Promises

Die JavaScript-Community verwendet Promises, um asynchronen Code wartbarer zu gestalten. Ein Promise repräsentiert eine asynchrone Funktion, deren Ergebnis vorliegt oder noch aussteht. Liefert eine asynchrone Funktion einen Promise zurück, kann der Aufrufer dessen Funktion then verwenden, um Funktionen als Callbacks zu registrieren. Die erste Funktion kommt zur Ausführung, wenn die asynchrone Funktion erfolgreich war; die zweite, wenn die asynchrone Funktion gescheitert ist:

someAsyncFunction().then(
function (rnd) { [...] },
// Success-Handler
function (error) { [...] }
// Error-Handler
);

Um die benötigten Objekte entgegenzunehmen, kommen in der Funktion Parameter zum Einsatz. Objekte werden auch als Abhängigkeiten (engl. Dependencies) bezeichnet. Beim Einsatz des Controllers übergibt nicht der Entwickler die Dependencies, sondern AngularJS – ein Vorgang der auch als Dependency Injection bekannt ist. Damit AngularJS die Abhängigkeiten injizieren kann, müssen die Namen der Parameter denen der zu injizierenden Abhängigkeiten (Services in AngularJS) entsprechen.

Im Beispiel kommen die Parameter $scope, $http und $q zum Einsatz. Der Parameter $scope zeigt auf ein Objekt, das Variablen, die in einem bestimmten Teil der Anwendung gültig sind, enthält. Die Aufgabe eines Controllers liegt im Bereitstellen von Informationen über dieses Objekt. Dabei handelt es sich um das Model im Sinne von MVC. Das Beispiel nutzt die dynamische Eigenschaft von JavaScript, um im Objekt $scope eine neue Eigenschaft vm einzurichten. Diese verweist auf das zu verwendende ViewModel. Dabei handelt es sich um ein Objekt von FlugBuchenVM.

Der Parameter $http bezeichnet einen Dienst, der im Lieferumfang von AngularJS enthalten ist und auf einfache Weise den Zugriff auf Ressourcen via HTTP erlaubt. Im Kontext von AngularJS werden Services als wiederverwendbare Objekte bezeichnet, die über Dependency Injection zu beziehen sind. $q ist ein Service, der sich zur Erzeugung von Promises heranziehen lässt und, wie der Name impliziert, von der populären JavaScript-Bibliothek Q inspiriert ist.