AngularUI Router, le ngRoute en mieux

⏲️ ~7 min de lecture

Publié le par Adrien
Angularjs JavaScript

Lors de la création d’application web monopage (single-page application) avec AngularJS, nous voulons que la navigation sur le site soit semblable à celle d’un site classique sans avoir à recharger notre page. AngularJS fournit ngRoute qui permet de réaliser ce routage.
UI-Router propose une vision différente afin de gérer la navigation sur notre application.

Dans tous les états #

Le framework de routing UI-Router offre une approche différente par rapport à ngRoute. Celui-ci permet de modifier les vues de votre application en fonction de l’état de celle-ci et non pas de l’URL.

Le gestionnaire d’état $stateProvider d'UI-Router est similaire au routeur d’AngularJS mais se concentre uniquement sur l’état de l’application. Un état peut être une URL, mais peut aussi être un moment ou une étape lors de la visite d’une page.

Un état correspond à un endroit de notre application en terme d’interface utilisateur et de navigation et décrit l’apparence et la logique de l’interface utilisateur à cet endroit.

Avantages #

ngRoute est un bon gestionnaire de navigation, mais UI Router va plus loin :

Mise en place #

La manière la plus simple de l'intégrer à notre projet est de télécharger les sources et de l'inclure dans notre index.html.

J'utilise personnellement Browserify (voir notre article sur le sujet) dans mes projets et installe donc ui-router via npm.

var modules = [require('angular-ui-router')];
// Si on n'utilise pas Browserify
// var modules = ['ui-router'];
var app = angular.module('myApp', modules);

La directive ui-view remplace le ng-view de ngRoute, les templates que nous définirons dans nos états seront automatiquement insérés dans la directive du template de leur état parent. Si on est dans un état qui n'a pas de parent, alors son template parent sera index.html.

N'oubliez pas le ui-view, sinon il ne se passera rien.

<

h2>C'est parti

Pour définir un état, nous allons déclarer une route à l'aide de la méthode .config comme on le ferait avec $routeProvider, mais à la place, nous allons utiliser $stateProvider

app.config(['$stateProvider', router]);

function router($stateProvider) {
    var mystate = {
        name = 'mystate',
        templateUrl: 'state.html'
    };

    $stateProvider
        .state(mystate);
};

On crée un petit fichier html pour notre état :


# Mon État

Activer un état #

Pour activer notre état, nous avons 3 méthodes :

La directive ui-sref permet de lier un lien (<a>) à un état. Si notre état possède une url, alors la directive va automatiquement générer le href de notre balise``.

Mon état

Un état plein de possibilités #

Définir un template #

Pour définir un template, il existe plusieurs possibilités :

Pour en savoir plus sur la configuration du template d'un état : Template

Ajouter un contrôleur #

Il existe plusieurs méthodes afin d'assigner un contrôleur au template d'un état (j'utilise la syntaxe "Controller as", mais il est possible d'utiliser le classique $scope).

Votre contrôleur ne sera pas intancié si vous n'avez pas défini de template.

var mystate = {
    template: '',
    controller: function() {
        this.name = 'Mon État';
    },
    controllerAs: 'Details'
};

Si votre contrôleur est déjà défini :

var mystate = {
    template: '',
    controllerAs: 'DetailsCtrl as Details'
};

Votre contrôleur sera directement accessible via Details dans votre template.

Vous voulez en savoir plus : la doc sur ce sujet.

La résolution des dépendances #

Le resolve, comme son nom l'indique, permet de résoudre des dépendances et de les injecter dans notre contrôleur. Dans le cas où notre resolve est une promesse, elle sera résolue avant l'instanciation du contrôleur ce qui permet, par exemple, de vérifier si l'utilisateur est connecté avant d'effectuer la transition d'état.

var mystate = {
    template: '',
    resolve: {
        name: function() {
            return 'Mon État';
        },
        httpPromise: function($http) {
            return $http.get('/users/isLoggedIn');
        }
    },
    controller: function(name, httpPromise) {
        this.name = name;
        this.loggedIn = httpPromise;
        if (!this.loggedIn) {
            $state.go('signin');
        }
    },
    controllerAs: 'Details'
};

Les URLs #

La forme simple de définition d'une URL pour notre état est la suivante :

var mystate = {
    url: '/state',
    template: '

# Mon État

'
};

Lorsque l'utilisateur va visiter l'adresse /state sur notre application, notre état va devenir actif et
inversement, si on active notre état (via ui-sref ou $state.go()), l'URL sera mise à jour vers l'URL de l'état.

Si vous voulez passer des attributs à votre état, la syntaxe suivante est disponible. Pour en savoir plus, reportez-vous à la doc très complète sur le sujet : URL Parameters

var mystate = {
    url: '/state/:stateLabel',
    template: '',
    controller: function($stateParams) {
        this.label = $stateParams.stateLabel;
    },
    controllerAs: 'State'
};

Héritage #

L'héritage permet d'imbriquer des états les uns dans les autres. Cette fonctionnalité vous permet de structurer efficacement la navigation de votre application et également de vos fichiers. En effet cette notion d'imbrication permet de modifier une partie de votre page à l'aide uniquement d'un directive ui-view dans votre template.

Un exemple de déclaration d'état imbriqué :

var country = {
    name: 'country',
    url: '/country',
    templateUrl: 'views/country/index.html',
};

var countryDetail ={
    name: 'country.detail',
    parent: country,
    url: '/detail',
    templateUrl: 'views/country/detail.html',
};

$stateProvider
    .state(country)
    .state(countryDetail);

Plusieurs choses concernant l'héritage :

Vues multiples #

Les vues multiples offrent la possibilité d'avoir plusieurs vues dans un même template, c'est intéressant pour les composants réutilisables type widget de votre application.

Imaginons que dans mon application ma page pays doit afficher une barre de navigation spéciale, une table comportant des données sur les pays et une représentation graphique de ces données. Je peux utiliser les vues multiples afin de séparer les vues et logique de chacun des "composants" de ma page de cette manière :


var country = {
    views: {
        'countriesNavbar': {
            templateUrl: 'countriesNavbar.html',
            controller: function(){ ... }
        },
        'countriesTable': {
            templateUrl: 'countriestable.html',
            controller: function(){ ... }
        },
        'countriesGraph': {
            templateUrl: 'countriesgraph.html',
            controller: function(){ ... }
        },
    }
};

$stateProvider
    .state('country');

On peut définir la logique de tous de nos templates dans leur contrôleurs respectifs.

Pour aller plus loin #

Les Les évenements de changement d'états ou encore les évenements de chargement de vue.

$urlRouterProvider vous servira à définir les redirections dans votre applications.

Et bien entendu la Documentation.

UI Router est un outil puissant qui vous permettra d'améliorer la navigation et la structure de votre application.
L'essayer c'est l'adopter, alors n'hésitez pas à nous faire vos retours d'expériences.

Cet article vous a plu ? Sachez que nous recrutons !

← Accueil