Проблема с ручной загрузкой и переопределением угловых сервисов в конфигурации

Я пытаюсь заставить мое угловое приложение работать в режиме реального времени, а также в режиме прототипа, просто переопределяя службы. Как часть этого, когда режим прототипа включен в конфигурации, я остановил процесс начальной загрузки, загрузил файлы mock services (js) и возобновил загрузку.

Вот упрощенный список исходного кода для подготовки демонстрации:

App.js

Просто мое приложение, которое для симуляции вызывает сервис и отображает результат. Требуется StubApp а также, чье обеспечение это собирается использовать для переопределения услуг

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

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

DataService.js

Просто простой сервис, зарегистрированный в приложении.

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

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 у которого есть список фиктивных сервисов, который загружается путем остановки начальной загрузки. Он также предоставляет предоставление, которое приложение может использовать для настройки перегрузки существующих служб с теми, что указаны в 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

Это просто макет, который на самом деле использует интерфейс заглушки для регистрации макета Stubs.module('app').mock(MockService) и у ctor есть свойство stubFor="serviceName" который говорит, какой сервис это на самом деле издевается

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

Просто простой файл JSON, который определяет макеты

["DataServiceMock.js"]

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 это больше не будет издеваться. Конкретная часть кода, которая выполняет переопределение в "StubProvider.js"

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

Вот демо Plnkr Если вы закомментируете строку в Driver.js вы можете видеть, что выходные данные будут получены от реального сервиса, в противном случае это будет макетный сервис. И повторить проблему в режиме index.html Driver.js до DataService.js он не отменяет DataService с MockDataservice.

  • Почему порядок регистрации конфигурации имеет значение, фаза конфигурации должна выполняться до того, как экземпляр службы все равно будет корректным?

  • Есть ли лучший шаблон, чтобы убедиться, что все сценарии загружены перед возобновлением процесса начальной загрузки, а не с использованием отложенного шаблона.

1 ответ

Использовать createElement а также appendChild DOM методы, src а также onload атрибуты script элемент, а bootstrap, element а также injector методы AngularJS:

    /* Create script element */
    var script = document.createElement('script');
    /* Set src */
    script.src = "https://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;

Другие вопросы по тегам