Problème avec l'amorçage manuel et la suppression des services angulaires dans config

J'essaie de faire fonctionner mon application angulaire en mode live ainsi que dans un mode prototype simplement en remplaçant les services. Dans ce cas, lorsque le mode prototype est activé dans la configuration, j'arrête le processus de démarrage, charge les services de simulation (js) et reprend l'amorçage.

Voici une liste simplifiée du code source pour préparer la démo : –

App.js

Juste mon application, qui pour la simulation appelle le service et affiche le résultat. Il lui fallait aussi StubApp qui fournirait ceci pour passer outre les services

 var app = angular.module('app', ['StubsApp']) .run([ '$rootScope', 'DataService', function($scope, DataService){ DataService.getData().then(function(data){ $scope.name = data; }); }]); 

DataService.js

Juste un service simple enregistré avec l'application.

 function DataService($q){ this.getData = function(){ return $q.when('I am Real!!'); } } DataService.$inject = ['$q']; angular.module('app').service('DataService',DataService); 

Driver.js

Juste l'enregistrement de configuration qui va se moquer.

 angular.module('app').config(['$provide', 'stubServiceProvider', 'AppConfig', function($provide, stubProvider, AppConfig){ if(AppConfig.StubEnabled){ stubProvider.loadStubsInModule('plunker'); } }]); 

StubProvider.js

Cela expose une interface similaire à angular.module pour enregistrer les services de stub. Il recherche également stubs.json qui a la liste des services simulés qui est chargé en arrêtant le bootstrap. Il expose également une offre qu'une application peut utiliser pour configurer une surcharge de services existants avec ceux dans les stubs.json

 var Stubs = {}, modules = []; function module(moduleName) { return { mock: function (func) { modules.push(func); }, get: function () { return modules; } }; } Stubs.module = module; loadStubs(); function loadStubs() { window.name = "NG_DEFER_BOOTSTRAP!"; var injector = angular.injector(['ng']); var $q = injector.get('$q'); var $http = injector.get('$http'); var scripts = []; $http.get('stubs.json').then(function (result) { scripts = result.data.map(function (src) { var script = document.createElement('script'); script.src = src; script.async = true; document.head.appendChild(script); var defered = $q.defer(); script.onload = function () { defered.resolve(); }; return defered.promise; }); $q.all(scripts).finally(function () { angular.element().ready(function () { angular.resumeBootstrap(); }); }); }); } //This is the provider which actually will do the overriding angular.module('StubsApp', []).provider('stubService', function ($provide) { ...... //Code in plunker }); 

DataService Mock.js

Il s'agit juste d'une simulation qui utilise l'interface Stubs pour enregistrer le Stubs.module('app').mock(MockService) et le ctor ont une propriété stubFor="serviceName" qui indique quel service se moque-t-il

 function MockService($q, $log){ this.getData = function(){ return $q.when('I am Mock!!'); } } MockService.$inject = ['$q', '$log']; MockService.stubFor="DataService"; Stubs.module('app').mock(MockService); 

Stubs.json

Juste un fichier json simple qui spécifie les moqueries

 ["DataServiceMock.js"] 

Index.html

 <script src="app.js"></script> <script src="DataService.js"></script> <script src="Driver.js"></script> <script src="stubprovider.js"></script> 

Cela fonctionne bien. Maintenant, le problème est que lorsque je déplace le fichier Driver.js avant l'enregistrement du service, c'est-à-dire DataService.js il ne se maquillera plus. La partie spécifique du code qui effectue la suppression dans "StubProvider.js" est

  Stubs.module(moduleName).get().forEach(function (mod) { var serviceName = mod.stubFor; var ctor = mod; if (serviceName) { $provide.service(serviceName, ctor); } }); 

Voici un Demo Plnkr Si vous avez commenté la ligne dans le Driver.js vous pouvez voir que la sortie sera du service réel, d'une manière ou d'une autre, du service de simulation. Et pour répliquer le problème dans le mode index.html Driver.js avant DataService.js il ne remplacera pas DataService par MockDataservice.

  • Pourquoi l'ordre de l'enregistrement de la configuration est-il important, la phase de configuration est-elle censée fonctionner avant que l'instanciation du service ne soit correcte?

  • Existe-t-il un meilleur modèle pour s'assurer que tous les scripts sont chargés avant de reprendre le processus bootstrap plutôt que d'utiliser le motif différé.

Utilisez les createElement et appendChild DOM, les attributs src et onload de l'élément script et les méthodes bootstrap , element et injector d'AngularJS:

  /* Create script element */ var script = document.createElement('script'); /* Set src */ script.src = "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js"; /* Append to head */ document.getElementsByTagName("head")[0].appendChild(script); function dothis() { //local datastore this.mvvm = {}; //template string var html = "<div>ID: {{$id}}</div>".replace("|",'"',"g"); //template object var template = angular.element(html); //template transformer var compiler = angular.injector(["ng"]).get("$compile"); //template result var linker = compiler(template); //scope object var scope = angular.injector(["ng"]).get("$rootScope"); //scope binding var result = linker(scope)[0]; /* Append result to body */ document.body.appendChild(result); /* Render */ angular.bootstrap(document, ['ng']); } script.onload = dothis;