AngularJS Component as Route

Routage AngularJS

Pour ceux qui ont commencé à se familiariser avec le router Angular 2, il peut sembler frustrant de continuer à utiliser le mode classique de routage de ui-router.
Normalement, on est obligé de spécifier pour une route / un state :

  • Un controller
  • Une url de template
  • Un template

exemple de configuration classique de state :

$stateProvider.state('contacts', {
  template: '

{{title}}

', controller: function($scope){ $scope.title = 'My Contacts'; } })

Si nous avons commencé à adopter les composants AngularJS 1.5, comment configurer ses routes avec des composants ?
Il existe des façons de configurer sa route avec le template d’un composant, la solution est détaillée dans cet article et se résume à ceci, pour un composant qui serait nommé Inbox :

$stateProvider.state('inbox', {
    url: '/inbox',
    template: '',

Mais cette solution n’est pas forcément très élégante.
Heureusement, bien caché dans les discussions des versions beta et alpha de ui-router, il existe une configuration de state avec un composant. Ça tombe bien car c’est une des recommandations du très sérieux Style Guide du très sérieux Todd Motto.

Configurer ui-router avec des composants

C’est une toute petite modification en apparence, mais ça va nous permettre de ne manipuler que des composants, et éliminer pour de bon ces scopes et autres rootScopes.
Voici une configuration de state :

.config(function ($stateProvider, $urlRouterProvider, $httpProvider) {

        var homeState = {
            name: 'home',
            url: '/',
            component: 'homeComponent'
};

Attention, comme nous ne manipulons plus le rootscope, nous n’allons pas intercepter les événements classiques de type stateChange, mais les transitions.
Comme on peut le voir sur cette page, cette configuration est encore sujette à modifications et je ne saurais dire si les exemples actuels seront toujours pertinents.
Voici comment capturer un changement de state avec cette version de ui-router :

.run(['$location', 'users', '$transitions', '$log',
    function ($location, users, $transitions, $log) {


        function restrictRoute($transitions) {
            // If the user is not authenticated
            if (!users.isAdmin()) {
                $log.debug("admin restricted");
                $transitions.router.stateService.go("home")
            } else {
                $log.debug("admin ok");
            }
        }
        $transitions.onStart( { to: 'admin' }, restrictRoute);

}]);

Injecter des objets dans les routes

Comme les composants sont injectés dans le router outlet, nous ne pouvons pas utiliser de binding dans le tag HTML.
Heureusement, on peut créer des bindings dans ce composant, directement depuis la configuration de la route, avec la méthode resolve.
Il suffit de déclarer l’objet resolve et de lui donner des propriétés qui pointent vers des fonctions, qui seront appelées directement, ou des Promise, qui devront être résolues pour que la route soit activée.

var adminState = {
            name: 'admin',
            url: '/admin',
            component: 'adminComponent', 
            resolve: {
                userLabel: function() {
                    return {value: "John"}
                }
            }
        };

// dans le composant
angular.module('pmApp.adminComponent', []).component('adminComponent', {
    ...
    bindings: {
        userLabel: "="
    }
});

Voilà une application qui ne comporte plus que des Component AngularJS 1.5 avec une jolie configuration de routes claire !

Pour accéder à une mini appli qui implémente ce système, voici le dépot github :
https://github.com/aboudard/angular1.5-router