Archives mensuelles : mai 2014

AngularJS : Migration de ngRoute vers AngularUI Router

Je viens d’effectuer la migration, de ngRoute (le gestionnaire de route par défaut d’angular) vers UI Router, le router fournit par le projet Angular UI (je vous conseille de regarder les différents modules qui peuvent être très pratique).

Le router fournit de base par Angular a quelques limitations et peut être pénalisant pour des applications complexes (Il a d’ailleurs été retiré d’Angular pour en faire un module à part depuis la version 1.2. La version 2.0 d’Angular devrait améliorer ce dernier et combler ses lacunes).

UI Router apporte notamment :

  • la gestion des vues imbriqués
  • Vues Multiples
  • resolve imbriqués
  • des directives
    • ui-sref pour la génération des liens
    • ui-sref-active pour ajouter une classe si un état est actif
  • des callbacks onEnter et onExit

Voici un petit tutoriel/retour d’expérience pour effectuer la migration vers UI Router. Dans mon cas, cela s’est très bien passé 🙂 ).

Migration

Installation

Le plus simple est d’installer angular-ui-router via bower avec la commande suivante :

bower install angular-ui-router --save

Il faut ensuite inclure le script dans votre page (pensez à supprimer l’inclusion du script de angular-route et à le supprimer de bower)

<script src="libs/angular-ui-router/release/angular-ui-router.js"></script>

Il faut également injecter la dépendance ui-router dans votre application (et supprimer celle de ngRoute)

angular.module('volleyApp',['ngRoute','angularCharts','ui.bootstrap'])

devient donc

angular.module('volleyApp',['ui.router','angularCharts','ui.bootstrap'])

ng-view est également à remplacer par ui-view.

<div ng-view></div>

Devient

<div ui-view></div>

Gestion des routes

Dans votre fichier de configuration des routes :

app.config(function ($routeProvider) {
  $routeProvider
    .when('/', {
      templateUrl: 'views/home.html',
      controller: 'HomeCtrl'
    })
    .when('/todo', {
      templateUrl: 'views/todo.html',
      controller: 'TodoCtrl'
    })
    //vos autres routes ...
    .when('/histo/stat/:matchId', {
      templateUrl: 'views/stat.html',
      controller: 'StatCtrl'
    })
    .otherwise({
      redirectTo: '/'
    });
});

devient

app.config(function ($stateProvider, $urlRouterProvider) {
  //Set default route
  $urlRouterProvider.otherwise('/');

  //Declare states
  $stateProvider
    .state('home', {
      url : '/',
      templateUrl: 'views/home.html',
      controller: 'HomeCtrl'
    })
    .state('todo', {
      url : '/todo',
      templateUrl: 'views/todo.html',
      controller: 'TodoCtrl'
    })
    //autres routes ...
    .state('stat', {
      url : '/histo/stat/:matchId',
      templateUrl: 'views/stat.html',
      controller: 'StatCtrl'
    });
});

Comme vous pouvez le voir, il n’y a pas grand à faire ici :

  • injecter les providers $stateProvider et $urlRouterProvider à la place de $routeProvider
  • Définition de la route par défaut via $urlRouterProvider.otherwise
  • remplacer when par state et donner un nom de vue (qui sera utiliser plus tard lors de l’utilisation de ui-sref)
  • rajouter un paramètre url pour chaque state.

Récupération des paramètres des routes

Dans ma vue de consultation des statistiques d’un match, j’utilise un paramètre dans l’url pour récuperer le match à consulter.

angular.module('volleyApp')
   .controller('StatCtrl', ['$scope', '$routeParams']
     function ($scope, $routeParams) {
       $scope.matchId = $routeParams.matchId;

Devient

angular.module('volleyApp')
   .controller('StatCtrl', ['$scope', '$stateParams']
     function ($scope, $stateParams) {
       $scope.matchId = $stateParams.matchId;

Ici non plus rien de très complexe. On injecte $stateParams à la place de $routeParams et on l’utilise.

Utilisation de ui-sref et ui-sref-active

UI Router fournit la directive ui-sref permettant la gestion des url.

<a class="btn btn-primary" href="#/histo/stat/{{$index}}>Stats</a>

Devient

<a class="btn btn-primary" ui-sref="stat({matchId: $index})>Stats</a>

Vous remarquerez que l’on utilise le nom du state vers lequel on souhaite être redirigé et que l’on passe les paramètres de l’URL via un objet.

ui-sref-active permet de d’ajouter des classes si l’état est sélectionné. Mon menu de navigation devient donc :

<nav>
  <ul class="nav nav-pills black">
    <li ui-sref-active="active"><a id="homeMenu" ui-sref="home">Home</a></li>
    <li ui-sref-active="active"><a id="matchMenu" ui-sref="match">Match</a></li>
    <li ui-sref-active="active"><a id="matchMenu" ui-sref="histo">Historique</a></li>
    <li ui-sref-active="active"><a id="todoMenu" ui-sref="todo">Todo</a></li>
  </ul>
</nav>

Karma

Si vous avez généré votre projet avec yeoman et que vous utilisez les tests unitaires avec karma, il faut également effectuer quelques changements :

  • Remplacer l’inclusion du angular-route.js par angular-ui-router.min.js dans la partie files du fichier karma.conf
  • Remplacer dans vos fichiers de tests l’utilisation de $routeParams par $stateParams.

Liens