Bien qu’AngularJS soit livré avec un routage intégré, vous pouvez parfois le trouver limitant ; le framework Angular UI Router peut aider à soulager la douleur. L’implémentation native du routage AngularJS est responsable de l’initialisation des contrôleurs qui correspondent aux routes de l’application. Bien que cette fonctionnalité fonctionne bien dans les scénarios de base, dans les situations avancées, vous constatez rapidement que le routage natif d’Angular :
- Vous oblige à modifier manuellement les chaînes d’URL dans toute votre base de code lorsqu’une URL change.
- Vous oblige à vous souvenir de la syntaxe de la route mot à mot pour naviguer vers une page.
- Ne propose pas de vues imbriquées.
- Ne propose pas de vues nommées.
- Ne vous permet pas de faire circuler des données pendant la navigation.
En guise d’alternative, le framework Angular UI Router est une couche d’abstraction pour le routage qui présente une approche plus déclarative de la navigation. Le framework UI Router comble également certaines des lacunes de l’implémentation native en fournissant des vues imbriquées et nommées, vous permet de passer des données entre les vues, et bien plus encore.
Le framework Angular UI Router est une couche d’abstraction pour le routage qui présente une approche déclarative de la navigation
Dans cet article, vous apprendrez à construire une application simple qui utilise le framework UI Router. En cours de route, vous vous familiariserez avec les états, la façon de résoudre les dépendances et vous apprendrez diverses méthodes de navigation.
- Comprendre les états
- Introducing Angular UI Router
- Navigation entre les états
- Téléchargement et installation
- Using Angular UI Router
- Configuration
- Définir les états
- Résolution des données avec le Articles Service
- Utilisation des données résolues dans le ArticlesController
- Rendu de la liste des articles
- Navigation plus abstraite
- Conclusion
Comprendre les états
Peut-être que la meilleure façon d’apprécier le problème que le framework UI Router espère résoudre est de considérer la nature du Web. Dans la plupart des applications, lorsque vous créez un lien vers une page, vous définissez un chemin URL explicite. Par exemple, si vous voulez naviguer vers la page Produits de votre site, vous pouvez avoir une URL comme:
Echantillon de code 1 : Version 2 Flexible Container
http://www.example.com/products
Cette situation pose deux problèmes. Le premier est que vous devez vous souvenir du chemin littéral exact vers la page Produits chaque fois que vous établissez un lien. Bien que l’exemple donné ici soit facile à retenir, de nombreuses URL du monde réel ne sont pas aussi faciles à mémoriser. Vous rencontrez le problème suivant lorsque l’inévitable se produit et que quelqu’un décide de changer le chemin d’accès en quelque chose d’autre. Lorsqu’une URL change, vous devez alors vous assurer que tous les liens existants sont mis à jour pour pointer vers le nouvel emplacement.
Au lieu de devoir garder la trace des chemins URL mot à mot, ne préféreriez-vous pas simplement dire à l’application d' »aller à la page des produits » ? En permettant à l’application de se préoccuper de la navigation, vous êtes dispensé de connaître le chemin littéral et vous êtes protégé des liens brisés causés par l’inévitabilité des changements. L’utilisation d’états vous offre ce niveau de flexibilité. Un état encapsule un emplacement URL, le nom de l’état, des données spécialisées pour la vue, identifie un moyen de localiser ou de générer la vue, et peut même exposer des événements personnalisés.
Introducing Angular UI Router
Angular UI Router est un cadre qui remplace entièrement le routage natif disponible dans AngularJS. L’UI Router est très similaire au routage natif d’AngularJS dans la mesure où les applications sont composées d’un shell qui contient un placeholder pour le contenu dynamique. La figure 1 montre comment le shell de l’application héberge un élément qui utilise la directive ui-view. Au fur et à mesure que les règles d’état sont évaluées dans le framework, le contenu HTML est rendu à l’intérieur du placeholder.
Angular UI Router est un framework qui remplace entièrement le routage natif disponible dans AngularJS.
Au delà du rendu du contenu HTML, le framework UI Router prend en charge le routage d’URL, la possibilité de résoudre les dépendances avant que les contrôleurs ne soient initialisés, les vues nommées et imbriquées, les filtres utilitaires, les événements de changement d’état et les transitions déclaratives entre les états.
Il existe plusieurs façons différentes que vous pouvez utiliser pour vous déplacer entre différents états. La première façon est la directive ui-sref. Vous êtes probablement familier avec l’attribut href de la balise d’ancrage HTML (qui représente une référence hypertexte) ; de la même façon, la directive ui-sref fait référence à une référence d’état. Vous utilisez la directive en déclarant un nom d’état avec la directive ui-sref appliquée à une ancre. Par exemple:
<a ui-sref="about">About Us</a>
Lorsque le framework UI Router évalue cette directive, l’ancre est transformée pour avoir la valeur URL appropriée. Par exemple:
<a ui-sref="about" href="#about">About Us</a>
Notez que l’élément est mis à jour pour inclure un attribut href avec une valeur correspondant à la façon dont l’URL doit être mise à jour pour naviguer vers la page À propos de nous. La directive ui-sref est assez flexible. Elle prend en charge des scénarios simples ainsi que des façons de traiter les états imbriqués et même les valeurs paramétrées.
L’approche suivante pour naviguer parmi les états est d’utiliser une méthode hors de l’objet $state qui est disponible pour un contrôleur Angular. Dans ce prochain extrait, vous pouvez voir comment la méthode navigate est mise en œuvre pour appeler $state.go et faire passer l’application à l’état about.
angular.module('app') .controller('PageController', );
L’objet $state est injecté par le framework UI Router et comprend un certain nombre de méthodes pour vous aider à gérer et à manipuler l’état dans l’application. La valeur ici est que vous dites à l’application d' »aller » à l’état about et vous êtes libéré de connaître le chemin URL littéral de la page.
Téléchargement et installation
Il existe un certain nombre de façons différentes d’accéder au framework UI Router. Vous pouvez télécharger la dernière version directement depuis le dépôt GitHub à https://github.com/angular-ui/ui-router. Alternativement, vous pouvez installer le framework via Bower ou NuGet ou même inclure des liens CDN dans vos pages ; les deux sont disponibles à http://cdnjs.com/libraries/angular-ui-router.
Using Angular UI Router
Ce qui suit est un tutoriel démontrant comment construire une application statique simple basée sur le contenu en utilisant le framework UI Router. La figure 2 représente l’exemple d’application de page d’accueil que vous apprenez à construire au fil de la lecture de cet article. Sur cette capture d’écran, vous pouvez voir le shell de l’application et comment le contenu de la page d’accueil est injecté dans le placeholder à l’aide de la directive ui-view.
Vous pouvez changer d’état pour naviguer vers la page de contact, comme le montre la figure 3. Le mécanisme de la page de contact utilise la méthode go de l’objet $state en passant un nom d’état à la méthode.
L’état suivant est associé à la page de liste de l’article, comme le montre la figure 4. Ici, un tableau de données d’articles est mis à disposition de la vue après que les valeurs brutes aient été injectées dans le contrôleur par l’UI Framework. La navigation sur cette page est facilitée par la directive ui-sref qui permet d’exprimer de manière déclarative l’état de l’application vers lequel on veut naviguer.
La dernière page, illustrée par la figure 5, montre comment un état imbriqué est utilisé dans l’application.
Configuration
Afin de commencer à travailler avec le framework UI Router, vous devez configurer la page. La première étape consiste à ajouter le nom de l’application dans l’attribut ng-app de l’élément HTML de la page. Ici, le nom de l’application est simplement app.
< html ng-app="app">
Puis, vous devez ajouter la directive ui-view à un élément de la page pour agir comme placeholder pour le contenu injecté par le framework. Dans cet exemple, la directive est ajoutée à un élément div.
< div ui-view></div>
Enfin, vous devez référencer à la fois Angular et Angular UI Router sur la page.
<script src="scripts/lib/angular.min.js"></script><script src="scripts/lib/angular-ui-router.min.js"></script><script src="scripts/app/app.js"></script>
Cet extrait de code comprend également une référence au script app.js dans le dossier script/app qui contient le code pour initialiser l’application Angular. Le processus d’initialisation est l’endroit où la plupart de la configuration et de l’interface avec le framework UI Router est mis en œuvre.
Définir les états
Comme indiqué précédemment, la base du framework UI Router est l’utilisation de différents états dans une application. En accédant à chacun de ces états, l’application peut naviguer vers ou se reconstituer en fonction des circonstances dans le cycle de vie de l’application. La section suivante montre comment définir les états de l’application ; l’ensemble du code est implémenté dans le fichier app.js. Chaque section est examinée isolément, mais si vous souhaitez voir le script d’initialisation complet, veuillez vous reporter au Listing 1.
La première étape consiste à configurer UI Router dans votre application AngularJS. Après avoir nommé le module, vous avez la possibilité d’enregistrer le framework UI Router comme une dépendance de l’application en ajoutant le littéral ui.router dans le tableau des dépendances. (Notez comment le commentaire dénote un espace réservé pour le code dans un extrait ultérieur.)
angular.module('app', ) .config(/* add configuration here */);
Une fois le module défini et les dépendances enregistrées, l’application est configurée pour exécuter une fonction anonyme qui s’exécute pendant la phase de configuration de l’application. Ici, il y a quelques ressources injectées dans la fonction qui sont pertinentes pour le framework UI Router.
L’objet $stateProvider présente la méthode state qui permet de définir des états granulaires de l’application qui peuvent coïncider ou non avec les changements de l’URL. L’objet $urlRouterProvider est un objet qui vous donne le contrôle sur la façon dont l’emplacement du navigateur est géré et observé. Dans le contexte du routeur d’interface utilisateur, $urlRouterProvider est utilisé pour aider à définir un scénario de navigation fourre-tout. Chacun de ces objets est abordé plus en détail dans les extraits de code suivants. (Encore une fois, notez que les extraits de code suivants sont placés à la position du commentaire placeholder dans l’extrait précédent.)
Chaque état d’application est défini en fournissant un nom et en indiquant au framework où trouver le balisage de la vue. Ici, l’état home est défini en fournissant l’emplacement racine de l’url et une valeur pour la propriété templateUrl.
$stateProvider .state('home', { url: '/', templateUrl: '/partials/home.html' })
Cela indique à l’application de charger le contenu du fichier home.html dans le placeholder ui-view lorsque l’utilisateur navigue vers la racine de l’application. Ici, vous commencez à voir l’un des avantages d’avoir un routage centré sur l’état. Si, pour une raison quelconque, vous vouliez que l’URL de l’état home pointe vers /home au lieu de l’emplacement de la racine nue (/), il suffirait d’effectuer ce changement ici dans la configuration. Cet état renonce à toute configuration avancée et charge une page statique dans le navigateur. Il peut y avoir d’autres fois où vous voulez associer un contrôleur spécifique à l’état.
L’état contact est configuré pour charger le balisage de la page contact.html dans le placeholder ui-view. Au-delà de l’exécution d’une opération de remplacement de base, le ContactsController est également associé à la vue scopée au niveau de l’élément DOM qui héberge la directive ui-view.
.state('contact', { url: '/contact', templateUrl: '/partials/contact.html', controller: 'ContactController', })
Comme le montre la figure 3, la page Contact comprend un bouton permettant de naviguer vers la page Articles. La navigation est effectuée dans le ContactsController et démontre comment câbler un contrôleur à une vue chargée à la demande par le framework UI Router.
L’état de la page Article pousse la configuration un peu plus loin en ajoutant des valeurs dans l’objet qui résout toutes les valeurs configurées définies dans l’objet. Le but de cet état est de rendre une liste des articles disponibles sur le site. Cet état est configuré pour que les informations sur les articles soient disponibles pour le contrôleur avant qu’il ne soit instancié. Dans le snippet suivant, l’état définit une valeur dans l’objet resolve.
.state('articles', { url: '/articles', templateUrl: '/partials/articles.html', resolve: { articles: 'ArticlesService' }, controller: 'ArticlesController' })
Dans ce cas, la propriété articles pointe vers la chaîne ArticlesService. Lorsque vous passez une chaîne comme valeur à la propriété resolve, le framework contacte un service enregistré sous le même nom et résout le service jusqu’à sa valeur finale. Dans ce cas, ArticlesService renvoie une promesse et le contrôleur associé n’est pas instancié tant que la promesse du service n’est pas résolue et que l’objet final n’est pas disponible en tant que valeur injectable pour le contrôleur. L’implémentation pour le ArticlesService est disponible dans le Listing 3.
Après que la liste des articles soit rendue à l’utilisateur, comme illustré dans la Figure 4, l’utilisateur peut sélectionner un article et forer dans le contenu du site. Cette action est représentée par un état imbriqué. Remarquez comment le nom de l’état comprend un point (.) entre articles et article pour indiquer une relation parent et enfant entre les états.
.state('articles.article', { url: '/:pageName', templateUrl: function ($stateParams) { return '/partials/articles/' + $stateParams.pageName + '.html'; } });
Ici, il y a une règle spéciale appliquée à la façon dont la propriété url est évaluée. Comme il s’agit d’une vue imbriquée (comme indiqué par le point dans le nom de l’état), la valeur de la propriété url sera concaténée avec la valeur url de l’état parent. Cela signifie que tout état correspondant aura une URL qui commence par /articles et inclut ensuite le nom de la page de l’article.
La présence des deux points ( 🙂 indique un paramètre d’URL. En introduisant un paramètre dans l’URL, la définition de l’état devient suffisamment flexible pour gérer n’importe quel état qui correspond à la relation qu’il a avec son état parent. Cet état comporte également une fonction qui est exécutée pour renvoyer la valeur de templateUrl. L’utilisation d’une fonction ici vous donne la possibilité d’utiliser les paramètres définis dans l’url de l’état. Le nom que vous donnez au paramètre dans la propriété url correspond au nom de la propriété de l’objet $stateParams. Par conséquent, cet état prend le pageName passé dans l’url pour l’utiliser dans la fonction templateUrl afin d’accéder aux fichiers de contenu individuels qui sont finalement injectés dans l’élément hébergeant la directive ui-view.
C’est le dernier état défini dans l’application. Pour voir comment tous les états sont mis en œuvre dans le script d’initialisation réel, consultez le Listing 1.
La dernière commande nécessaire à donner à l’application est ce qu’il faut faire si l’utilisateur essaie d’accéder à une URL qui n’est pas définie dans la méthode configure. En utilisant la méthode otherwise de l’objet $urlRouterProvider, toute URL non reconnue est écartée et l’application est redirigée vers un emplacement par défaut. Dans cet exemple, l’application est configurée pour rediriger vers l’URL racine si l’URL donnée ne correspond pas à un état défini.
$urlRouterProvider.otherwise('/');
Maintenant, avec chaque état d’application défini, vous pouvez commencer à porter votre attention sur la construction du ArticlesService.
Résolution des données avec le Articles Service
La configuration de l’état de l’article comprend une valeur pour l’option resolve. Cet objet est configuré pour avoir une valeur de chaîne de caractères de ArticlesService définie sur la propriété articles (voir le Listing 1 pour le contexte). La fourniture d’une chaîne à l’objet resolve indique au framework de localiser un service enregistré dans l’application et de résoudre le service jusqu’à sa valeur finale. Le ArticlesService est implémenté pour retourner une promesse.
angular.module('app').factory('ArticlesService', ); return deferred.promise; }]);
Ici, le service utilise le service $q pour créer une promesse pour retourner un tableau. Dans ce cas, les valeurs sont codées en dur, mais dans un contexte réel, vous pouvez avoir besoin d’accéder à un serveur distant pour fournir les données. Dans tous les cas, le service doit être entièrement résolu avant que le framework du routeur ne passe l’exécution au contrôleur associé. Par conséquent, comme l’état de l’article est invoqué, en fin de compte, le contrôleur reçoit un tableau d’objets d’article comme dépendance.
Utilisation des données résolues dans le ArticlesController
L’un des avantages de l’utilisation du framework UI Router est la possibilité d’appliquer la séparation des préoccupations. Comme l’état des articles implémente un objet resolve, le tableau brut des articles est injecté dans le contrôleur.
angular.module('app') .controller('ArticlesController', );
Cette approche est supérieure à la nécessité pour le ArticlesController de « connaître » le ArticlesService car il est beaucoup plus facile de mocker un tableau brut d’objets à des fins de test plutôt que de traiter le mocking du service lui-même. L’implémentation complète pour les contrôleurs de l’application se trouve dans le Listing 2.
Rendu de la liste des articles
Maintenant que l’application a navigué vers l’état de l’article et que le contrôleur a le tableau d’articles résolu mis en scope, la vue est maintenant prête à être rendue. La vue Articles est composée de deux parties. La première est un autre div placeholder qui utilise la directive ui-view afin de créer une vue imbriquée. La seconde est une liste non ordonnée des différents articles disponibles sur le site. En construisant la vue de cette manière, vous pouvez cliquer sur différents titres d’articles tout en conservant la liste des articles sur la page. (Cela est possible parce que le contenu de la page est chargé dans l’ui-view au niveau de l’article tandis que la page dans son ensemble est rendue dans l’ui-view du shell de l’application. L’implémentation complète du shell d’application est disponible dans le Listing 4.
L’extrait de code suivant démontre comment la vue articles implémente une vue imbriquée.
<div ui-view> <!-- default content goes here --></div>...<ul class="list-group"> <li class="list-group-item" c> <a ui-sref="articles.article({pageName: '{{article.pageName}}'})"> {{article.title}}</a> </li></ul>
Il y a trois façons dont ce balisage utilise le framework UI Router. Tout d’abord, l’élément div utilise la directive ui-view en tant que placeholder et, comme l’indique le commentaire, vous pouvez transmettre un contenu par défaut à rendre dans le placeholder avant que tout contenu ne soit rendu par le framework. Le Listing 5 démontre comment un message statique est utilisé comme contenu placeholder sur la page avant que tout contenu ne soit chargé dans la vue.
Deuxièmement, l’élément anchor a la directive ui-sref appliquée. Cela signale au framework UI Router de traiter ce lien dans le contexte du framework et rend finalement une valeur href standard qui correspond à l’URL de l’état déclaré en fonction des paramètres définis dans la configuration de l’application (voir Listing 1).
La troisième façon dont le framework est utilisé est que la valeur de la directive ui-sref accepte une expression pour générer la valeur d’URL correcte pour un état imbriqué. Ici, un hachage est passé dans la hiérarchie des états imbriqués (dans ce cas articles.article) où la valeur de pageName est liée au pageName de l’article entrant. Lorsque le framework UI Router évalue cette expression, une valeur URL correspondante est générée pour chaque article qui correspond aux règles d’état définies.
Le dernier contrôleur à mettre en œuvre est le ContactController, qui utilise la méthode go du paramètre d’état pour faire naviguer l’application vers un nouvel état.
app.controller('ContactController', );
Ici, en appelant simplement go avec un nom d’état, votre contrôleur est seulement concerné par la déclaration de l’état vers lequel vous souhaitez changer plutôt que d’essayer de garder une trace du schéma de routage concret dans l’application.
Conclusion
Bien qu’AngularJS soit fourni avec une implémentation de routage fonctionnelle, vous pouvez rapidement réaliser les avantages de l’utilisation d’un cadre de routage basé sur l’état pour les applications non triviales. Le framework UI Router fournit des moyens faciles pour vous de définir des états, de résoudre les dépendances et d’utiliser des vues imbriquées. Pour encore plus d’informations sur ce que le framework peut faire, assurez-vous de visiter la maison du projet sur GitHub à https://github.com/angular-ui/ui-router/.