© DrHitch/Shutterstock.com
Moderne Webanwendungen mit AngularJS

2 Weitere Konzepte von AngularJS und Features


Im vorherigen Kapitel haben wir ein AngularJS-Projekt mit dem Namen Cube angelegt. Cube ist eine einfache Anwendung zur Visualisierung eines dreidimensionalen Würfels, bei dem wir den X-, Y- und Z-Rotationsgrad steuern können (Abb. 2.1). Wir haben gelernt, dass wir mithilfe der Zwei-Wege-Datenbindung eine Ansicht ziemlich einfach automatisch aktualisieren können, wenn sich die zugrunde liegenden Daten geändert haben. Auch den umgekehrten Fall, also die automatische Aktualisierung der Datenschicht bei Änderungen in der Ansicht, deckt dieses Konzept ab. Daher kommt auch der Begriff der Zwei-Wege-Datenbindung.

Außerdem haben wir uns angeschaut, wie wir ein eigenes <cube>-Tag entwerfen können, das den gesamten HTML-Code und die Logik kapselt, die nötig ist, um einen dreidimensionalen Würfel darzustellen. Wir können einen solchen Würfel sehr einfach erzeugen, indem wir in einem Template unser <cube>-Tag verwenden:

<cube init-x="20" init-y="100" init-z="5"></cube>
<cube init-x="100" init-y="20" init-z="20"></cube>
<cube init-x="0" init-y="0" init-z="0"></cube>

In diesem Kapitel des shortcuts wollen wir uns weitere Konzepte von AngularJS anschauen, indem wir unser Cube-Projekt um einige Features erweitern. Zunächst werden wir einen Mechanismus implementieren, um dynamisch weitere Würfel erstellen und vorhandene Würfel wieder löschen zu können. Bisher lässt sich das nur zur Entwicklungszeit bewerkstelligen, indem wir in der index.html weitere <cube>-Tags einbauen bzw. vorhandene <cube>-Tags entfernen.

Weiterhin werden wir uns anschauen, welche Möglichkeiten uns das Framework bietet, um eine HTTP-basierte Schnittstelle anzusprechen. Hierzu werden wir das Flickr-API nutzen, um die sechs Seiten eines Würfels mit einem Hintergrundbild zu versehen.

Flickr bietet uns die Möglichkeit, unsere Fotos in der Cloud zu verwalten und mit anderen Menschen zu teilen. Öffentliche Fotos können von allen Besuchern durchsucht werden und über das Flickr-API abgerufen werden.

Verschmutze niemals unnötig den Root Scope!

Mit der Einführung des neuen Scope für den <body>-Abschnitt bewahren wir unseren Root Scope vor einer unnötigen Verschmutzung und verbessern insgesamt die Struktur unserer Anwendung. Ähnlich wie bei dem globalen Namensraum einer JavaScript-Anwendung im Browser sollten wir immer danach streben, den Root Scope möglichst unangetastet zu lassen.

Controller und Scopes

Wir haben in der letzten Ausgabe bereits gelernt, dass das MVVM Pattern (Model View ViewModel) das grundlegende Architekturmuster in AngularJS ist. Die so genannten ViewModels tragen den Namen Scopes und legen einen Geltungsbereich für Variablen fest, die in einem bestimmten Teil unserer Ansicht gelten und zur Ausgabe genutzt werden können. Wir wissen außerdem bereits, dass jede AngularJS-Anwendung genau einen Root Scope besitzt, von dem alle anderen Scopes prototypisch erben.

Nun gibt es einige Komponenten, für die das Framework einen eigenen Scope erstellt. Wir haben bei unserer cube-Direktive bereits gesehen, dass Direktiven zu solchen Komponenten gehören können, wenn wir im Direktiven-Definitions-Objekt (DDO) die scope-Eigenschaft auf true setzen oder ihr ein Konfigurationsobjekt zuweisen. Um außerhalb von Direktiven für einen bestimmten Abschnitt des DOMs einen eigenen Scope zu erstellen, nutzen wir Controller. Ein Controller definiert also eine Konstruktionsvorschrift für einen neuen Scope.

Um das Feature zum Einfügen bzw. Löschen eines Würfels zu implementieren, wollen wir für den DOM-Abschnitt unterhalb des <body>-Elements zunächst einen neuen Scope erzeugen. Als Konstruktionsvorschrift für diesen Scope soll der CubeListCtrl-Controller dienen, dessen Definition wir in Listing 2.1 nachvollziehen können. Das <body>-Element annotieren wir somit mit der ngController-Direktive und weisen ihr den Wert CubeListCtrl zu:

<body ng-controller="CubeListCtrl">
[...]
</body>
tarasiewicz1.tif

Abb. 2.1: Stand des Cube-Projekts aus dem ersten Teil

Natürlich müssen wir für den CubeListCtrl-Controller zunächst die entsprechende JavaScript-Datei mit dem Namen cubeListCtrl.js erstellen. Diese Datei legen wir in dem Verzeichnis app/scripts/controllers/ ab. Dazu müssen wir offensichtlich in dem scripts-Verzeichnis zunächst noch das controllers-Verzeichnis erstellen. Schließlich müssen wir die Datei cubeListCtrl.js – wie üblich – in unserer index.html mit einem <script>-Tag einbinden.

<script src="lib/angular/angular.js"></script>
<script src="scripts/module.js"></script>
<script src="scripts/directives/cubeDirective.js"></script>
<script src="scripts/controllers/cubeListCtrl.js"></script>

Wie wir in Listing 2.1 nachvollziehen können, definieren wir unseren CubeListCtrl-Controller – genau wie die cube-Direktive – in unserem Anwendungsmodul cubeApp. Dazu nutzen wir die controller()-Funktion von AngularJS. Sie erwartet zwei Parameter. Mit dem ersten legen wir den Namen des Controllers fest (hier: CubeListCtrl). Als zweiten Parameter wird eine Funktion erwartet, die die Konstruktionsregeln für den Scope enthält, den das Framework durch die Verwendung der ngController-Direktive für den <body>-Abschnitt erzeugt. Diese Funktion wird in den meisten Fällen, wie auch hier, nicht benannt und ist somit eine anonyme Funktion. Wir können in Listing 2.1 außerdem erkennen, dass uns AngularJS in der anonymen Funktion eine Referenz auf den neu erstellten Scope als Parameter übergibt ($scope). Dazu nutzt das Framework intern Dependency Injection (Kasten: „Dependency Injection in AngularJS“).

angular.module("cubeApp")
.controller("CubeListCtrl", function ($scope) {
$scope.cubes = [
{x: 20, y: 100, z: 5},
{x: 100, y: 20, z: 20},
{x: 0, y: 0, z: 0}
];
});

Listing 2.1:cubeListCtrl.js

Dependency Injection in AngularJS

Um Abhängigkeiten automatisch aufzulösen, nutzt AngularJS das Konzept der Dependency Injection. Wie wir bei der cube-Direktive und beim CubeListCtrl-Controller nachvollziehen können, werden die meisten Komponenten so definiert, dass wir die entsprechende Framework-Funktion (z. B. directive(), controller() usw.) mit zwei Parametern aufrufen: Dem Namen der Komponente und einer (meistens anonymen) Funktion, die die Konstruktionsvorschrift für die Komponente bereitstellt. In dieser Funktion können wir in Form von Parametern beliebig viele Abhängigkeiten spezifizieren, die uns das Framework übergeben soll. Ausschlaggebend für die Abhängigkeitsauflösung ist dabei der Name der Parameter. So fordern wir das Framework z. B. in dem CubeListCtrl-Controller mit dem Parameter $scope dazu auf, uns eine Referenz auf den Scope zu übergeben.


Somit können wir in diesem Scope beliebige Variablen definieren, die wir in der entsprechenden Ansicht nutzen wollen und die durch die Zwei-Wege-Datenbindung automatisch aktualisiert werden sollen. In Listing 2.1 definieren wir auf diese Weise die Scope-Variable cubes, die eine Referenz auf ein Array mit drei Objekten enthält. Jedes dieser Objekte besitzt die Eigenschaften x, y und z, die offensichtlich die drei Rotationsgrade eines Würfels beschreiben.

Au...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang