web-dev-qa-db-fra.com

Collision des modules et des espaces de noms/noms dans AngularJS

Considérez le code suivant jfiddle http://jsfiddle.net/bchapman26/9uUBU/29/

//angular.js example for factory vs service
var app = angular.module('myApp', ['module1', 'module2']);

var service1module = angular.module('module1', []);

service1module.factory('myService', function() {
    return {
        sayHello: function(text) {
            return "Service1 says \"Hello " + text + "\"";
        },
        sayGoodbye: function(text) {
            return "Service1 says \"Goodbye " + text + "\"";
        }
    };
});

var service2module = angular.module('module2', []);

service2module.factory('myService', function() {
    return {
        sayHello: function(text) {
            return "Service2 says \"Hello " + text + "\"";
        },
        sayGoodbye: function(text) {
            return "Service2 says \"Goodbye " + text + "\"";
        }
    };
});

function HelloCtrl($scope, myService) {
    $scope.fromService1 = myService.sayHello("World");
}

function GoodbyeCtrl($scope, myService) {
    $scope.fromService2 = myService.sayGoodbye("World");
}​

J'ai 2 modules (module1 et module2). Les modules1 et module2 définissent tous deux un service appelé myService. Cela semble créer un conflit de noms sur myService dans Angular lorsque les deux modules sont importés dans myApp. Il semble que AngularJs utilise simplement la deuxième définition de service sans vous avertir du problème possible.

Les très grands projets (ou simplement la réutilisation de modules en général) risqueraient d'entraîner des conflits de noms pouvant être difficiles à déboguer.

Existe-t-il un moyen de préfixer les noms avec le nom du module afin que les conflits de noms ne se produisent pas? 

48
Brian Chapman

À ce jour, les modules AngularJS ne fournissent aucune sorte d'espacement de nom empêchant les collisions entre les objets de différents modules. La raison en est qu’une application AngularJS a un seul injecteur qui contient les noms de tous les objets sans tenir compte des noms de modules.

Le Guide du développeur AngularJS dit:

Pour gérer la responsabilité de la création de dépendance, chaque angulaire l'application a un injecteur. L'injecteur est un localisateur de service qui est responsable de la construction et de la recherche de dépendances.

Comme vous l'avez mentionné, de mauvais bugs peuvent survenir lors de l'injection de modules dans votre module principal/d'application. En cas de collision, ils sont silencieux et le gagnant est déterminé par le dernier module injecté.

Donc non, il n'y a pas de moyen construit pour éviter ces collisions. Peut-être que cela se produira dans le futur. Pour les grandes applications où ce problème devient plus probable, vous avez raison de dire que les conventions de dénomination sont votre meilleur outil. Déterminez si les objets appartenant à un module ou à une zone de fonction peuvent utiliser un préfixe court. 

62
Jim Ierley

Vous pouvez éviter cette situation en utilisant une convention pour nommer vos modules afin qu'ils soient toujours uniques.

Une approche consiste à examiner comment les autres langues le font. Par exemple, en Java, le «nom complet» de la classe dépend du nom du fichier et du dossier dans lequel il se trouve. Par exemple, si vous aviez un fichier Java appelé Bitmap.Java dans le dossier MyArtStuff, le nom complet de la classe être MyArtStuff.Bitmap

AngularJS vous permet d’avoir des points (.) Dans le nom de votre module afin que vous puissiez essentiellement utiliser la convention de nom.

Par exemple, si un développeur crée un module appelé «ModuleA» dans le script «MainPage\Module1.js», il doit nommer son module «MainPage.Module1.ModuleA». Parce que chaque chemin et nom de fichier est unique dans votre application, le nom de votre module sera unique.

Il vous suffirait d’amener vos développeurs à suivre cette convention.

Notez que, comme le souligne Rockallite, cela n’aidera pas les services, les contrôleurs, etc., ayant le même nom dans plusieurs modules. Mais vous pouvez utiliser une approche similaire pour obtenir cela et préfixer les noms de ces éléments.

Dans l’idéal, AngularJS aurait des espaces de noms et pourrait le devenir à l’avenir. Jusque-là, le mieux que nous puissions faire est de faire ce que les développeurs font depuis plus de 40 ans avant que les espaces de noms ne soient inventés et de préfixer au mieux nos éléments.

2
Luis Perez

Malheureusement, il n'y a pas namespacing dans AngularJS. Une solution consiste à utiliser un prefix (une autre solution peut être this !). Voir l'exemple suivant:

// root app
const rootApp = angular.module('root-app', ['app1', 'app2']);

// app 1
const app1 = angular.module('app1', []);
app1.controller('app1.main', function($scope) {
  $scope.msg = 'App1';
});

// app2
const app2 = angular.module('app2', []);
app1.controller('app2.main', function($scope) {
  $scope.msg = 'App2';
})
<!-- [email protected] -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.0/angular.min.js"></script>

<!-- root app -->
<div ng-app="root-app">

  <!-- app 1 -->
  <div ng-controller="app1.main">
    {{msg}}
  </div>

  <!-- app 2 -->
  <div ng-controller="app2.main">
    {{msg}}
  </div>

</div>

0
Yas