AngularJS 1.x und 2.0 mit dem Component Router parallel betreiben

Seite 2: Views

Inhaltsverzeichnis

Ähnlich wie bei ngRoute und UI Router können Routen auch Parameter, die mit einem Doppelpunkt eingeleitet werden, aufweisen:

$router.config([
[...]
{ path: '/passagier/:id, component: 'passagierEdit' }
]);

Zum Auslesen des Parameters innerhalb des adressierten Controllers können Entwickler den Service $routeParams injizieren. Dieser weist für jeden Parameter eine Eigenschaft auf:

var id = $routeParams.id; // Liefert z.B. 7 für /passagier/7

Um anzugeben, wo die View der aktiven Route zu platzieren ist, ist im Markup der Single Page Application ein Platzhalter vorgesehen. In der hier betrachteten Version 0.5.x des Component Router kommt dafür die Direktive ngViewport zum Einsatz. In der endgültigen Version soll sie jedoch wahrscheinlich ngOutlet heißen:

[...]
<body ng-controller="AppController as app">
[...]
<ul class="nav navbar-nav">
<li><a ng-link="home">Home</a></li>
<li><a ng-link="flugBuchen">Flug Buchen</a></li>
</ul>
[...]
<div>
<div ng-viewport></div>
</div>

<script src="jspm_packages/system.js"></script>
<script src="config.js"></script>
<script>
System.import('app').catch(console.error.bind(console));
</script>
[...]

Das betrachtete Markup referenziert über ng-controller den AppController, der die Routen bereitstellt. Die Direktive ngLink kümmert sich um das Einrichten von Links, die zu diesen Routen führen. Am Ende des Markups werden der Modul-Loader System.js sowie die hierfür genutzte Konfiguration config.js geladen. Der Aufruf von System.import sorgt für das Einbinden der zuvor betrachteten Datei app.js samt ihrer direkten und indirekten Abhängigkeiten.

Ähnlich wie der De-facto-Standard UI Router unterstützt Component Router auch hierarchisch organisierte Views. Dabei handelt es sich um Views, die Platzhalter für weitere Views aufweisen. Um dieses Konzept zu nutzen, können Entwickler einen Component Router in einen über das Routing geladenen Controller injizieren. Mit diesem sogenannten Child Router lassen sich weitere untergeordnete Routen festlegen.

Der nachfolgende Codeauszug demonstriert das. In ihm sind über den FlugBuchenController, der über den Pfad /flugbuchen erreichbar ist, weitere Routen festgelegt. Darunter befindet sich beispielsweise eine für den Pfad /passagier. Da es sich hierbei um eine untergeordnete Route handelt, erhält sie den vollständigen Pfad /flugbuchen/passagier. Beim Aktivieren dieser Route lädt der Child Router die Komponente passagier und somit einen PassagierController sowie eine View /components/passagier/passagier.html. Damit er Letztere zur Anzeige bringen kann, muss die View des übergeordneten FlugBuchenController einen Platzhalter aufweisen. Dazu ist abermals die Direktive ngViewport zu nutzen.

export class FlugBuchenController {
constructor($router) {
$router.config([
{ path: '/passagier', component: 'passagier' },
{ path: '/flug', component: 'flug' }
]);
}
[...]
}

Der neue Component Router gibt Entwicklern auch die Möglichkeit, mehrere Platzhalter pro Single Page Application beziehungsweise pro View zu nutzen. In dem Fall sind sie angehalten, den Platzhaltern Namen zu geben, die später an die Direktive ngViewport weiterzureichen sind:

<div ng-viewport="main"></div>
<hr>
<div ng-viewport="info"></div>

Die Routing-Konfiguration legt darüber hinaus fest, welche Komponente in welchen Platzhalter zu laden ist:

export class FlugBuchenController {
constructor($router) {
$router.config([
{ path: '/passagier', components: { main: 'passagier',
info: 'flugBuchenInfo' } },
{ path: '/flug', components: { main: 'flug', info:
'flugBuchenInfo' }, as:'flug' }
]);
}
}

Um auf solch eine Route zu verweisen, sind ngLink der Name eines Platzhalters sowie der dazugehörige Komponentenname zu übergeben:

<a ng-link="main:flug">Flug</a>

In Fällen, in denen die Kombination nicht eindeutig ist, können Entwickler der Route auch durch Angabe der Eigenschaft as einen Alias geben und via ngLink darauf verweisen. Ein Beispiel dafür findet sich in einem GitHub-Repository des Autors.

Um ein Eingreifen in das Routing zu ermöglichen, stellt der Component Router sogenannte Lifecycle Hooks zur Verfügung. Damit sie sich einsetzen lassen, sind die Controller mit einer oder mehrerer der folgenden Methoden zu versehen:

Methode Beschreibung
canActivate wird vor Aktivierung einer Route ausgeführt
activate wird nach Aktivierung einer Route ausgeführt
canDeactivate wird vor Verlassen einer Route ausgeführt
deactivate wird nach dem Verlassen einer Route ausgeführt

Durch das Zurückliefern von false unterbindet der Controller den jeweiligen Routen-Wechsel. Auf die Weise kann er das Verlassen einer Route ohne Speichern ebenso verhindern, wie das Aktivieren einer Route, für die der Benutzer nicht die nötigen Berechtigungen hat. Letzteres dient bei Single Page Applications mehr der Benutzerfreundlichkeit und weniger der Sicherheit.

Ist der Controller nicht sofort in der Lage zu entscheiden, ob der Routenwechsel durchgeführt werden darf, kann er auch ein Promise zurückliefern. Lässt es sich später erfolgreich auflösen (resolve), erfolgt der Routenwechsel. Kommt es dabei hingegen zu einem Fehler (reject), bricht der Router den Vorgang ab. Ein Beispiel für die Nutzung dieser Lifecycle Hooks findet sich im auf GitHub bereitgestellten Code zum vorliegenden Text innerhalb des PassagierEditControllers.