Javascript 配置中手动引导和覆盖angular services的问题

Javascript 配置中手动引导和覆盖angular services的问题,javascript,angularjs,angularjs-service,Javascript,Angularjs,Angularjs Service,我正试图通过覆盖服务,使我的angular应用程序在实时模式和原型模式下工作。当原型模式在配置中打开时,我会停止引导过程,加载模拟服务(js)文件并恢复引导 以下是用于准备的源代码的简化列表:- App.js 只有我的应用程序,用于模拟调用服务并显示结果。它需要StubApp以及将使用谁的提供来覆盖服务 DataService.js 只需在应用程序中注册一个简单的服务 Driver.js 只需设置模拟的配置注册 angular.module('app').config(['$provide',

我正试图通过覆盖服务,使我的angular应用程序在实时模式和原型模式下工作。当原型模式在配置中打开时,我会停止引导过程,加载模拟服务(js)文件并恢复引导

以下是用于准备的源代码的简化列表:-

App.js

只有我的应用程序,用于模拟调用服务并显示结果。它需要
StubApp
以及将使用谁的提供来覆盖服务

DataService.js

只需在应用程序中注册一个简单的服务

Driver.js

只需设置模拟的配置注册

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

这将公开一个类似于
angular.module
的接口来注册存根服务。它还查找
stubs.json
,其中包含通过停止引导加载的模拟服务列表。它还公开了一个provide,应用程序可以使用它设置stubs.json中现有服务的过载

DataService Mock.js

这仅仅是一个mock,它实际使用Stubs接口来注册mock
Stubs.module('app').mock(MockService)
,并且ctor有一个属性
stubFor=“serviceName”
,它告诉我们它实际模拟的是哪个服务

stubs.json

只是一个简单的json文件,用于指定模拟

index.html

<script src="app.js"></script>
<script src="DataService.js"></script>
<script src="Driver.js"></script>
<script src="stubprovider.js"></script>
这里有一个如果您注释掉
Driver.js
中的行,您可以看到输出将来自真实服务,另一方面,它将来自模拟服务。要在
DataService.js
之前以index.html模式
Driver.js
复制该问题,它不会用MockDataservice覆盖DataService

  • 为什么配置注册的顺序很重要,配置阶段应该在服务实例化正确之前运行?

  • 是否有更好的模式确保在恢复引导过程之前加载所有脚本,而不是使用延迟模式


使用
createElement
appendChild
DOM方法、
src
onload
属性以及AngularJS的
bootstrap
元素
injector
方法:

/*创建脚本元素*/
var script=document.createElement('script');
/*设置src*/
script.src=”https://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js";
/*附在头上*/
document.getElementsByTagName(“head”)[0].appendChild(脚本);
函数dothis()
{
//本地数据存储
this.mvvm={};
//模板字符串
var html=“ID:{{$ID}}”。替换(“|“,”,“g”);
//模板对象
var template=angular.element(html);
//模板转换器
var compiler=angular.injector([“ng”]).get(“$compile”);
//模板结果
var linker=编译器(模板);
//范围对象
var scope=angular.injector([“ng”]).get($rootScope”);
//范围绑定
var结果=链接器(范围)[0];
/*将结果附加到正文*/
document.body.appendChild(结果);
/*渲染*/
引导(文档,['ng']);
}

script.onload=dothis;
我喜欢这个问题,因为我现在无法回答。我一直在玩你的代码,我有一个问题。你为什么不创建一个新模块,提供你想要覆盖的所有内容,从主模块到刚刚创建的模块,然后将模块名传递给resumeBootstrap函数?这样你就可以uld能够覆盖以前定义的所有名称。它应该更干净。我想到的另一个选择是使用装饰器,但我认为它们不适用于您的场景。干杯!希望有一个更好的答案来给Sooon更多值得注意的东西,angular.injector()启动应用程序,但我不知道当window.name是NG_DEFER_BOOTSTRAP时它的行为是什么!@HeberLZ谢谢你的建议,实际上听起来是个好主意。我还没有尝试过。但是如果你得到一个好的/更好的解决方案,请作为答案发布。我的主要问题是,我不想在html st中加载模拟控制器的脚本当然。我会动态加载它。再次感谢。提供引导的想法是,在我们调用resumeBootstrap之前,引导不会启动。我认为问题不在引导流程中,而是在注入器创建过程中。我之所以这样说,是因为我试着根本不同步引导应用程序,而是执行引导手动关闭,结果完全相同。另一方面,我必须在执行时声明注入器,它们像并行应用程序一样工作,这就是为什么我认为这可能是导致这种奇怪行为的原因。稍后我将尝试一些方法,如果结果是肯定的,则显示结果。干杯!
angular.module('app').config(['$provide', 'stubServiceProvider', 'AppConfig', function($provide, stubProvider, AppConfig){
    if(AppConfig.StubEnabled){
       stubProvider.loadStubsInModule('plunker');
    }
}]);
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
});
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);
["DataServiceMock.js"]
<script src="app.js"></script>
<script src="DataService.js"></script>
<script src="Driver.js"></script>
<script src="stubprovider.js"></script>
   Stubs.module(moduleName).get().forEach(function (mod) {
        var serviceName = mod.stubFor;
        var ctor = mod;
        if (serviceName) {
            $provide.service(serviceName, ctor);
        }
    });