Utiliser les modèles dans AngularJS

⏲️ ~3 min de lecture

Publié le par Adrien
Angularjs JavaScript

Dans cet article, nous allons effectuer une séparation efficace des contrôleurs et des modèles dans une application AngularJS afin de rendre notre code plus simple, lisible et maintenable.

Le contrôleur pas tout à fait modèle #

La mauvaise interprétation du célèbre patron d'architecture MVC, utilisé par AngularJS, a souvent pour conséquence une utilisation abusive des contrôleurs en leur donnant également le comportement des modèles. Pourtant, comprendre comment les différentes parties du MVC intéragissent entre-elles dans un framework est important pour l'évolution et la maintenabilitéd'une application.

Vous avez surement rencontré des exemples de contrôleurs qui gèrent l’état des données ou encore implémentent de la logique métier alors qu'ils ne devraient probablement pas.
La responsabilité d'un contrôleur est de communiquer avec le modèle et non d'être le modèle.

Par exemple :

App.controller('StockCtrl', function($location, $http) {
    this.products = [];

    this.showProduct = function(product) {
        $location.path('/product').search('id', product.id);
    };

    this.deleteProduct = function(product) {
        $http.post('/product/delete', product)
        .success(function(data) {
            this.products.splice(products.indexOf(product), 1);
        });
    };

    this.stockPrice = function() {
        return this.products.reduce(function(sum, product) {
            return (product.price * product.count) + sum;
        }, 0);
    };

    $http.get('/products')
    .success(products(data) {
        this.products = data;
    });

});

Ce contrôleur, par ailleurs semblable à ceux que l'on retrouve dans la documentation d'AngularJS : https://docs.angularjs.org/api/ng/directive/ngController, permet de gérer un stock de produits.

Pour un prototype, ce contrôleur est suffisant. Dans le cas d'une applications plus conséquente, c'est une mauvaise pratique. En effet avec ce code, comment ré-utiliser l'action de suppression d'un produit dans un autre contrôleur ? Cette implémentation va nous faire dupliquer du code ou utiliser des hacks pour arriver à nos fins.

Un modèle qui gère ses données #

Pour remédier à ce problème, nous allons utiliser le Modèle du patron MVC et déplacer toute la logique métier et surtout confier la responsabilité de l'état des données à notre modèle.
Pour créer notre modèle, nous allons utiliser une Factory

App.factory('Product', function($http) {
    var Product = {};
    Product.products = [];

    Product.getAll = function() {
        return $http.get('/products')
        .success(function(data) {
            this.products = data;
        });
    };

    Product.delete = function(product) {
        $http.post('/post/delete', product)
        .success(function() {
            this.products.splice(this.products.indexOf(product), 1);
        });
    };

    Product.totalPrice = function() {
        return this.products.reduce(function(sum, product) {
            return (product.price * product.count) + sum;
        }, 0);
    };

    return Product;
});

Et voila, nous avons désormais un modèle injectable que nous pouvons facilement ré-utiliser dans le reste de notre application.

Simplifier le contrôleur #

Ensuite nous allons faire subir une cure d’amaigrissement à notre contrôleur pour n'avoir plus aucune création ou modification de données dans celui-ci.

App.controller('StockCtrl', function($location, Product) {
    this.products = Product.products;

    this.showproduct = function(product) {
        $location.path('/product').search('id', product.id);
    };

    this.deleteproduct = function(product) {
        Product.delete(product);
    };

    this.stockPrice = function() {
        Product.totalPrice();
    };

    Product.getAll()
    .then(function() {
        this.products = Product.products;
    }.bind(this));

});

Le contrôleur est simplifié, plus lisible et n'est plus responsable de l'état des données. C'est important car les contrôleurs sont crées et détruits souvent dans le cycle de vie d'une application AngularJS.

Ré-utilisons notre modèle #

Nous pouvons maintenant utiliser le modèle Product dans le reste de notre application :

App.controller('StatCtrl', function($scope, Product) {
    $scope.products = Product.products;

    $scope.watchCollection('products', function() {
        $scope.stockPrice = Product.totalPrice();
    });
});

Ce contrôleur peut par exemple permettre la création d'un widget qui affichera le prix total de notre stock.

Notre contrôleur a retrouvé son rôle initial d’intermédiaire entre la vue et le modèle. Le code est simple et respecte la séparation entre le modèle et le contrôleur.

Cet article vous a plu ? Sachez que nous recrutons !

← Accueil