问题在配置手动引导和压倒一切的角度服务 [英] Issue with manual bootstrapping and overriding angular services in config

查看:110
本文介绍了问题在配置手动引导和压倒一切的角度服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想只是通过重写服务,以获得在现场模式,以及在原型模式我的角度应用程序的工作。作为这项工作的一部分,当原型模式在config打开,我停止引导过程,加载模拟服务(JS)文件,并恢复引导。

下面是源$ C ​​$ C为preparing在演示 -

App.js

只是我的应用程序,这对于模拟调用服务并显示结果。它要求 StubApp 以及其提供这要使用覆盖服务

  VAR应用= angular.module('应用',['StubsApp']).RUN(['$ rootScope','DataService的',函数($范围的DataService){
   DataService.getData()。然后(功能(数据){
    $ scope.name =数据;
  });
}]);

DataService.js

只是与应用程序注册一个简单的服务。

 函数的DataService($ Q){
  this.getData =功能(){
       返回$ q.when(我是真正的!!');
  }
}
。DataService的$注射='$ Q'];
angular.module(应用)服务(DataService的',DataService的)。

Driver.js

只需在配置登记​​将设立嘲讽。

  angular.module(应用)。配置(['$提供,stubServiceProvider','AppConfig的',函数($提供,stubProvider,AppConfig的){
    如果(AppConfig.StubEnabled){
       stubProvider.loadStubsInModule('plunker');
    }
}]);

StubProvider.js

这暴露了类似于 angular.module 的接口以注册存根服务。它也查找 stubs.json 里面有哪些是通过暂停引导加载的模拟服务的列表。这也暴露了它提供了一个应用程序可以用它来建立与那些现有服务的过载在stubs.json

  VAR存根= {},
    模块= [];
功能模块(MODULENAME){
    返回{
        模拟:功能(FUNC){
            modules.push(FUNC);
        },得到:函数(){
            返回模块;
        }
    };
}
Stubs.module =模块;loadStubs();功能loadStubs(){
    window.name =NG_DEFER_BOOTSTRAP!;
    VAR喷油器= angular.injector(['NG']);
    变量$ Q = injector.get('$ Q');
    变量$ HTTP = injector.get('$ HTTP');
    变种脚本= [];    $ http.get('stubs.json'),然后(功能(结果){
        脚本= result.data.map(功能(SRC){
            VAR脚本=使用document.createElement('脚本');
            script.src = SRC;
            script.async = TRUE;
            document.head.appendChild(脚本);            变种延迟执行= $ q.defer();            script.onload =功能(){
                defered.resolve();
            };
            返回defered.promise;
        });        $ q.all(脚本)。最后(函数(){
            angular.element()。就绪(函数(){
                angular.resumeBootstrap();
            });
        });
    });
}//这是真正会做的首要提供商
angular.module('StubsApp',[])。提供商('stubService',函数($提供){
    ...... // code在plunker
});

的DataService Mock.js

这是只是其中实际使用存根接口注册模拟 Stubs.module(应用)。模拟(MockService)和构造函数的模拟有一个属性 stubFor =服务名它告诉哪些服务这实际上嘲笑

 函数MockService($ Q $日志){
this.getData =功能(){
       返回$ q.when(我是模拟!');
  }
}
。MockService $注射='$ Q','$日志'];MockService.stubFor =DataService的;。Stubs.module(应用)模拟(MockService);

stubs.json

只是一个简单的JSON文件,指定的嘲笑

  [DataServiceMock.js]

的index.html

 <脚本SRC =app.js>< / SCRIPT>
&所述; SCRIPT SRC =DataService.js>&下; /脚本>
&所述; SCRIPT SRC =Driver.js>&下; /脚本>
&所述; SCRIPT SRC =stubprovider.js>&下; /脚本>

这工作正常。现在的问题是,当我在服务注册之前,移动 Driver.js 文件 DataService.js 就不会再嘲笑。的code,在StubProvider.js进行覆盖特定部分。

  Stubs.module(模块名)获得()的forEach(函数(MOD){
        VAR服务名= mod.stubFor;
        VAR构造函数= MOD;
        如果(服务名){
            $ provide.service(服务名,构造函数);
        }
    });

下面是一个 演示Plnkr 如果你注释掉 Driver.js 行,你可以看到输出将是真正的服务其他明智这将是从模拟服务。并在复制中的index.html模式问题 Driver.js DataService.js 则无法覆盖的DataService与MockDataservice。


  • 为什么在配置的注册事项的顺序,配置阶段应该运行前的服务实例反正正确?


  • 有没有更好的方式,以确保所有脚本恢复引导过程,而不是使用递延模式之前被加载。



解决方案

使用的createElement 的appendChild DOM方法中,的src 的onload 属性的剧本元素,和引导元素注射器 AngularJS的方法:

\r
\r

/ *创建脚本元素* /\r
    VAR脚本=使用document.createElement('脚本');\r
    / *设置SRC * /\r
    script.src =htt​​p://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js;\r
    / *附加到头部* /\r
    document.getElementsByTagName(头)[0] .appendChild(脚本);\r
    \r
    功能dothis()\r
      {\r
      //本地数据存储\r
      this.mvvm = {};\r
    \r
      //模板字符串\r
      VAR HTML =< D​​IV> ID:{{$ ID}}< / DIV>中。替换(|,',G);\r
      //模板对象\r
      VAR模板= angular.element(HTML);\r
      //模板变压器\r
      。VAR编译器= angular.injector([NG])获得($编译);\r
      //模板结果\r
      变种接头=编译器(模板);\r
      //对象范围\r
      。VAR范围= angular.injector([NG])获得($ rootScope);\r
      //范围结合\r
      VAR的结果=连接器(范围)[0];\r
    \r
      / *追加结果身体* /\r
      document.body.appendChild(结果);\r
    \r
      / * *渲染/\r
      angular.bootstrap(文件,['NG']);\r
      }\r
    \r
    script.onload = dothis;

\r

\r
\r

I am trying to get my angular application work in live mode as well as in a prototype mode just by overriding the services. As a part of this when the prototype mode is turned on in the config, i halt the bootstrap process, load mock services (js) files and resume bootstrapping.

Here is a simplified list of source code for preparing the demo:-

App.js

Just my app, which for simulation calls the service and display the result. It required StubApp as well whose provide this is going to use to override the services

var app = angular.module('app', ['StubsApp'])

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

DataService.js

Just a simple service registered with the app.

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

Driver.js

Just the config registration which will set up mocking.

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

StubProvider.js

This exposes an interface similar to angular.module to register stub services. it also looks for stubs.json which has the list of mock services which is loaded by halting the bootstrap. It also exposes a provide which an App can use to set up overload of existing services with the ones in the 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

This is the just a mock which actually uses Stubs interface to register the mock Stubs.module('app').mock(MockService) and the ctor has a property stubFor="serviceName" which tells which service this actually mocks

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

Just a simple json file that specifies the mocks

["DataServiceMock.js"]

index.html

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

This works fine. Now the issue is that when i move Driver.js file before the service registration i.e DataService.js it won't mock anymore. Specific portion of code that performs overriding in the "StubProvider.js" is

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

Here is a Demo Plnkr If you comment out the line in the Driver.js you can see the output will be from the real service other wise it will be from the mock service. And to replicate the issue in the index.html mode Driver.js before DataService.js it won't override DataService with MockDataservice.

  • Why is it that the order of config registration matter, config phase is supposed to run before the service instantiation anyways correct?

  • Is there a better pattern to ensure all the scripts are loaded before resuming the bootstrap process rather than using the deferred pattern.

解决方案

Use the createElement and appendChild DOM methods, the src and onload attributes of the script element, and the bootstrap, element and injector methods of 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;

这篇关于问题在配置手动引导和压倒一切的角度服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆