web-dev-qa-db-fra.com

Meilleures pratiques AngularJS pour la déclaration de module?

J'ai un tas de modules angulaires déclarés dans mon application. J'ai initialement commencé à les déclarer en utilisant la syntaxe "chained" comme ceci:

angular.module('mymodule', [])
    .controller('myctrl', ['dep1', function(dep1){ ... }])
    .service('myservice', ['dep2', function(dep2){ ... }])
    ... // more here

Mais j'ai décidé que ce n'était pas très facile à lire, alors j'ai commencé à les déclarer en utilisant une variable de module comme celle-ci:

var mod = angular.module('mymodule', []);

mod.controller('myctrl', ['dep1', function(dep1){ ... }]);

mod.service('myservice', ['dep2', function(dep2){ ... }]);
...

La deuxième syntaxe me semble beaucoup plus lisible, mais le seul reproche que je puisse faire est que cette syntaxe laisse la variable mod dans la portée globale. Si j’ai une autre variable nommée mod, elle sera remplacée par celle-ci (ainsi que par d’autres problèmes associés aux variables globales).

Ma question est donc la suivante: est-ce le meilleur moyen? Ou serait-il préférable de faire quelque chose comme ça?:

(function(){
    var mod = angular.module('mymod', []);
    mod.controller('myctrl', ['dep1', function(dep1){ ... }]);
    mod.service('myservice', ['dep2', function(dep2){ ... }]);
    ...
})();

Ou est-ce même assez important pour s'en soucier? Juste curieux de savoir quelles sont les "meilleures pratiques" pour la déclaration de module. Merci d'avance.

113
tennisgent

Meilleur moyen de déclarer un module

Comme angular est sur la portée globale elle-même et que les modules sont enregistrés dans sa variable, vous pouvez accéder aux modules via angular.module('mymod'):

// one file
// NOTE: the immediately invoked function expression 
// is used to exemplify different files and is not required
(function(){
   // declaring the module in one file / anonymous function
   // (only pass a second parameter THIS ONE TIME as a redecleration creates bugs
   // which are very hard to dedect)
   angular.module('mymod', []);
})();


// another file and/or another anonymous function
(function(){   
 // using the function form of use-strict...
 "use strict";
  // accessing the module in another. 
  // this can be done by calling angular.module without the []-brackets
  angular.module('mymod')
    .controller('myctrl', ['dep1', function(dep1){
      //..
    }])

  // appending another service/controller/filter etc to the same module-call inside the same file
    .service('myservice', ['dep2', function(dep2){ 
    //... 
    }]);

  // you can of course use angular.module('mymod') here as well
  angular.module('mymod').controller('anothermyctrl', ['dep1', function(dep1){
      //..
  }])
})();

Aucune autre variable globale n'est requise.

Bien sûr, tout dépend des préférences, mais je pense que c’est un peu la meilleure pratique, comme 

  1. vous n'avez pas à polluer la portée mondiale
  2. vous pouvez accéder à vos modules partout et les trier et leurs fonctions dans différents fichiers à volonté
  3. vous pouvez utiliser la forme de fonction "use strict";
  4. l'ordre de chargement des fichiers importe moins

Options de tri de vos modules et fichiers

Cette façon de déclarer et d’accéder aux modules vous rend très flexible. Vous pouvez trier les modules par type de fonction (comme décrit dans une autre réponse) ou par route, par exemple:

/******** sorting by route **********/    
angular.module('home')...
angular.module('another-route')...
angular.module('shared')...

La manière dont vous le triez à la fin dépend des goûts personnels, de l’ampleur et du type du projet. Personnellement, j'aime bien regrouper tous les fichiers d'un module dans le même dossier (classés dans des sous-dossiers de directives, de contrôleurs, de services et de filtres), y compris tous les différents fichiers de test, afin de rendre vos modules plus réutilisables. Ainsi, dans les projets de taille moyenne, je me retrouve avec un module de base, qui inclut tous les itinéraires de base et leurs contrôleurs, services, directives et sous-modules plus ou moins complexes, alors que je pense qu'ils pourraient également être utiles pour d'autres projets, par exemple: :

/******** modularizing feature-sets **********/
/controllers
/directives
/filters
/services
/my-map-sub-module
/my-map-sub-module/controllers
/my-map-sub-module/services
app.js
...

angular.module('app', [
  'app.directives',
  'app.filters',
  'app.controllers',
  'app.services',
  'myMapSubModule'
]);

angular.module('myMapSubModule',[
   'myMapSubModule.controllers',
   'myMapSubModule.services',
   // only if they are specific to the module
   'myMapSubModule.directives',
   'myMapSubModule.filters'
]);

Pour les très grands projets, je finis parfois par regrouper des modules par itinéraires, comme décrit ci-dessus, ou par certains itinéraires principaux sélectionnés ou même par une combinaison d'itinéraires et de certains composants sélectionnés, mais cela dépend vraiment.

EDIT: Tout simplement parce que c'est lié et que je l'ai retrouvé très récemment: Veillez à ne créer un module qu'une seule fois} _ (en ajoutant un second paramètre à la valeur angulaire .module-fonction). Cela va gâcher votre application et peut être très difficile à détecter.

2015 EDIT sur les modules de tri:} _ Après un an et demi d'expérience angulaire, je peux ajouter que les avantages liés à l'utilisation de modules portant un nom différent dans votre application sont quelque peu limités, car AMD ne fonctionne toujours pas vraiment. bien avec Angular et services, les directives et les filtres sont globalement disponibles dans le contexte angulaire ( comme illustré ici ). Cependant, il y a toujours un avantage structurel et sémantique et il pourrait être utile de pouvoir inclure/exclure un module avec une seule ligne de code commentée.

Il est également presque il n’est jamais logique de séparer les sous-modules par type} (par exemple. 'MyMapSubModule.controllers'), car ils dépendent généralement les uns des autres. 

117
hugo der hungrige

J'adore le angular-styleguide de Johnpapa, et voici quelques règles relatives à cette question:

Rule: Nommé vs Fonctions Anonymes

Évitez d'utiliser des fonctions anonymes:

// dashboard.js
angular
  .module('app')
  .controller('Dashboard', function() { })

À la place, utilisez des fonctions nommées:

// dashboard.js
angular
  .module('app')
  .controller('Dashboard', Dashboard);

function Dashboard() { }

Comme le dit l'auteur: This produces more readable code, is much easier to debug, and reduces the amount of nested callback code.

Règle: Définir 1 composant par fichier. 

Évitez les composants multiples dans un fichier:

angular
  .module('app', ['ngRoute'])
  .controller('SomeController', SomeController)
  .factory('someFactory', someFactory);

function SomeController() { }

function someFactory() { }

Intead, utilisez un fichier pour définir le module:

// app.module.js
angular
  .module('app', ['ngRoute']);

un fichier utilise simplement le module pour définir un composant

// someController.js
angular
  .module('app')
  .controller('SomeController', SomeController);

function SomeController() { }

et un autre fichier pour définir un autre composant

// someFactory.js
angular
  .module('app')
  .factory('someFactory', someFactory);

function someFactory() { }

Bien sûr, il existe de nombreuses autres règles pour les modules, les contrôleurs et les services qui sont très utiles et méritent d'être lues.

Et grâce au commentaire de ya_dimon, le code ci-dessus devrait être enveloppé dans IIFE, par exemple:

(function (window, angular) {
  angular.module('app')
   .controller('Dashboard', function () { });
})(window, window.angular);
27
aqingsao

J'ai récemment eu cette énigme aussi. J'avais commencé comme vous en utilisant la syntaxe chaînée, mais à la longue, cela devient difficile à manier avec des projets volumineux. Normalement, je créais un module de contrôleurs, un module de services, etc. dans des fichiers séparés et les injectais dans le module principal de l'application que l'on trouve dans un autre fichier. Par exemple:

// My Controllers File
angular.module('my-controllers',[])
    .controller('oneCtrl',[...])
    .controller('twoCtrl',[...]);

// My Services File
angular.module('my-services',[])
    .factory('oneSrc',[...])
    .facotry('twoSrc',[...]);

// My Directives File
angular.module('my-directives',[])
    .directive('oneDrct',[...])
    .directive('twoDrct',[...]);

// My Main Application File
angular.module('my-app',['my-controllers','my-services','my-directives',...]);

Mais chacun de ces fichiers devenait de plus en plus volumineux à mesure que le projet prenait de l'ampleur. J'ai donc décidé de les séparer en fichiers distincts en fonction de chaque contrôleur ou service. J'ai trouvé que vous avez besoin de angular.module('mod-name'). sans la matrice d'injection pour que cela fonctionne. Déclarer une variable globale dans un fichier et s'attendre à ce qu'elle soit facilement disponible dans un autre ne fonctionne tout simplement pas et peut avoir des résultats inattendus.

En bref, mon application ressemblait à ceci:

// Main Controller File
angular.module('my-controllers',[]);

// Controller One File
angular.module('my-controllers').controller('oneCtrl',[...]);

//Controller Two File
angular.module('my-controllers').controller('twoCtrl',[...]);

Je l'ai également fait dans le fichier de services, pas besoin de changer le fichier de module d'application principal, car vous y injecteriez toujours les mêmes modules.

12
m.e.conroy

Une autre pratique consiste à insérer les contrôleurs, les directives, etc. dans leurs propres modules et à les insérer dans votre module "principal":

angular.module('app.controllers', [])
  .controller('controller1', ['$scope', function (scope) {
    scope.name = "USER!";
  }]);

angular.module('app.directives', [])
  .directive('myDirective', [function () {
    return {
      restrict: 'A',
      template: '<div>my directive!</div>'
    }
  }]);

angular.module('app', [
  'app.controllers',
  'app.directives'
]);

Rien n'est laissé dans la portée globale.

http://plnkr.co/edit/EtzzPRyxWT1MkhK7KcLo?p=preview

8
Manny D

J'aime diviser mes fichiers et mes modules.

Quelque chose comme ça:

app.js

var myApp = angular.module('myApp', ['myApp.controllers', 'myApp.directives', 'myApp.services']);

myApp.config(['$routeProvider', function($routeProvider) {
    /* routes configs */
    $routeProvider.when(/*...*/);
}]);

directives.js

var myDirectives = angular.module('myApp.directives', []);

myDirectives.directive( /* ... */ );

service.js

var myServices = angular.module('myApp.services', []);

myServices.factory( /* ... */ );

Je ne suis pas un grand fan du "style chaîné", je préfère donc toujours écrire ma variable.

4
Beterraba

Pour moi, le chaînage est le moyen le plus compact:

angular.module("mod1",["mod1.submod1"])

 .value("myValues", {
   ...
 })

 .factory("myFactory", function(myValues){
   ...
 })

 .controller("MainCtrl", function($scope){

   // when using "Ctrl as" syntax
   var MC = this;
   MC.data = ...;
 })
 ;

De cette façon, je peux facilement déplacer des composants entre les modules, ne jamais avoir besoin de déclarer le même module deux fois, jamais besoin de variables globales.

Et si le fichier est trop long, la solution est simple: elle est divisée en deux fichiers, chacun déclarant son propre module en haut. Pour plus de transparence, j'essaie de conserver un module unique par fichier et de le nommer, qui ressemble au chemin d'accès complet du fichier. De cette façon, je n'ai jamais besoin d'écrire un module sans [], ce qui est un problème récurrent.

0
Dmitri Zaitsev

Je suggère de suivre Guide de style Angularjs .
Ils gèrent tous les concepts, de la convention de nommage, à la modularisation de votre application, etc.

Pour Angular 2, vous pouvez vérifier Angular 2 Style Guide

0
user3444693