Problema com inicialização manual e substituição de serviços angulares na configuração
Estou tentando fazer com que meu aplicativo angular funcione no modo ao vivo e no modo de protótipo apenas substituindo os serviços. Como parte disso, quando o modo de protótipo está ativado na configuração, interrompo o processo de inicialização, carrego arquivos de serviços simulados (js) e continuo a inicialização.
Aqui está uma lista simplificada de código fonte para preparar odemonstração: -
App.js
Apenas meu aplicativo, que para simulação chama o serviço e exibe o resultado. ExigiaStubApp
bem como quem fornecer isso vai usar para substituir os serviços
var app = angular.module('app', ['StubsApp'])
.run([ '$rootScope', 'DataService', function($scope, DataService){
DataService.getData().then(function(data){
$scope.name = data;
});
}]);
DataService.js
Apenas um serviço simples registrado com o aplicativo.
function DataService($q){
this.getData = function(){
return $q.when('I am Real!!');
}
}
DataService.$inject = ['$q'];
angular.module('app').service('DataService',DataService);
Driver.js
Apenas o registro de configuração que irá configurar a zombaria.
angular.module('app').config(['$provide', 'stubServiceProvider', 'AppConfig', function($provide, stubProvider, AppConfig){
if(AppConfig.StubEnabled){
stubProvider.loadStubsInModule('plunker');
}
}]);
StubProvider.js
Isso expõe uma interface semelhante aangular.module
para registrar serviços de stub. também procurastubs.json
que tem a lista de serviços simulados que são carregados interrompendo a inicialização. Também expõe um fornecimento que um aplicativo pode usar para configurar a sobrecarga de serviços existentes com os 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
Este é apenas um mock que realmente usa a interface Stubs para registrar o mockStubs.module('app').mock(MockService)
e o ctor tem uma propriedadestubFor="serviceName"
que diz qual serviço isso realmente zomba
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
Apenas um arquivo json simples que especifica as zombarias
["DataServiceMock.js"]
index.html
<script src="app.js"></script>
<script src="DataService.js"></script>
<script src="Driver.js"></script>
<script src="stubprovider.js"></script>
Isso funciona bem. Agora, a questão é que quando eu mudoDriver.js
Arquivoantes do registro do serviço isto éDataService.js
não vai mais zombar. Parte específica do código que executa a substituição no "StubProvider.js" é
Stubs.module(moduleName).get().forEach(function (mod) {
var serviceName = mod.stubFor;
var ctor = mod;
if (serviceName) {
$provide.service(serviceName, ctor);
}
});
Aqui está umDemo Plnkr Se você comentar a linha noDriver.js
você pode ver que a saída será do serviço real, caso contrário, será do serviço simulado. E para replicar o problema no modo index.htmlDriver.js
antesDataService.js
ele não substituirá o DataService pelo MockDataservice.
Por que a ordem do registro da configuração é importante, a fase de configuração deve ser executada antes que a instanciação do serviço seja corrigida?
Existe um padrão melhor para garantir que todos os scripts sejam carregados antes de retomar o processo de autoinicialização em vez de usar o padrão adiado.