Angular: загружать свойства среды перед конфигурацией/запуском

Я разрабатываю угловое приложение, и это приложение имеет около 10 настраиваемых свойств (в зависимости от среды и клиента).

У меня были эти свойства в файлах конфигурации json, но это действительно проблематично: должны быть определенные сборки для каждой env/company. Поэтому я хотел бы получить эти свойства один раз из бэкэнда при загрузке приложения.

Поэтому для этого я создал Provider

var app = angular.module('myApp', [...]);
app.provider('environment', function() {
    var self = this;
    self.environment;

    self.loadEnvironment = function (configuration, $http, $q) {
        var def = $q.defer();
        $http(...)
        .success(function (data) {
            self.environment = Environment.build(...);
            def.resolve(self.environment);
        }).error(function (err) {
            ...
        });
        return def.promise;
    };

    self.$get = function(configuration, $http, $q) {
        if (!_.isUndefined(self.environment)) {
            return $q.resolve(self.environment);
        }
        return self.loadEnvironment(configuration, $http, $q);
    };
}
app.config(... 'environmentProvider', function(... environment) {
    ...
    //The problem here is that I can't do environment.then(...) or something similar... 
    //Environment does exists though, with the available functions... 
}

Как правильно работать с этим провайдером, который выполняет вызов rest для заполнения своей переменной среды?

Заранее спасибо!


person Thomas Stubbe    schedule 18.10.2016    source источник
comment
Какой замечательный сценарий, приятель :D! А если серьезно, вы бы не возражали, если бы среда была constant или value? Я думаю, что это лучший подход.   -  person lenilsondc    schedule 18.10.2016
comment
@thomas, вы используете какие-либо инструменты сборки, такие как gulp?   -  person krutkowski86    schedule 18.10.2016
comment
Использование grunt (а для некоторых сборок даже maven над ним)... Приложение имеет огромную область применения, и мы используем константы atm, но этого недостаточно...   -  person Thomas Stubbe    schedule 18.10.2016


Ответы (1)


Это отличный сценарий для изучения возможностей angularjs.

Предполагая, что вам действительно нужны данные среды, загруженные до загрузки приложения, вы можете использовать инструменты angular для загрузки среды, а затем объявить value или constant для хранения конфигураций вашей среды перед загрузкой приложения.

Таким образом, вместо использования ng-app для запуска приложения необходимо использовать angular.bootstrap для его загрузки вручную.

Примечания. Вы не должны использовать ng-app после загрузки приложения вручную, иначе ваше приложение будет загружаться с системой angular по умолчанию без учета загрузки вашей среды. Кроме того, обязательно загрузите приложение после объявления всех компонентов модуля; т. е. объявить все контроллеры, службы, директивы и т. д., поэтому вы вызываете angular.bootstrap

В приведенном ниже коде реализовано решение, описанное ранее:

(function() {
    var App = angular.module("myApp", []);

    // it will return a promisse of the $http request
    function loadEnvironment () {
        // loading angular injector to retrieve the $http service
        var ngInjector = angular.injector(["ng"]);
        var $http = ngInjector.get("$http");

        return $http.get("/environment-x.json").then(function(response) {
            // it could be a value as well
            App.constant("environment ", response.data);
        }, function(err) {
            console.error("Error loading the application environment.", err)
        });
    }

    // manually bootstrap the angularjs app in the root document
    function bootstrapApplication() {
        angular.element(document).ready(function() {
            angular.bootstrap(document, ["myApp"]);
        });
    }

    // load the environment and declare it to the app
    // so then bootstraps the app starting the application
    loadEnvironment().then(bootstrapApplication);
}());
person lenilsondc    schedule 18.10.2016
comment
Многообещающий ответ! Раньше я реализовывал то же самое, но без углового контекста (так что просто $.get(...) и затем начал загрузку), позвольте мне попробовать! - person Thomas Stubbe; 18.10.2016
comment
Как бы вы совместили app.config([...]) и app.run(...) с этим? В настоящее время я получаю ошибки неизвестного провайдера (банкомат для $q) - person Thomas Stubbe; 18.10.2016
comment
Итак, что я делаю, это var app = angular.module('myApp', [... lot of providers...]); app.config([...some providers and environment..., function(...) { ... }); app.run(...); function loadEnvironment() { ... returns promise... } function bootstrapApplication() { angular.element(document).ready(function () { angular.bootstrap(document, ['myApp']); }); } loadEnvironment().then(bootstrapApplication, function (err) { console.log(err); }); - person Thomas Stubbe; 18.10.2016
comment
Вы можете разделить это в правильном порядке, просто не забудьте объявить все, прежде чем загружать свое приложение. Например, вы можете объявить свой модуль отдельно, а затем просто использовать геттер для извлечения модуля следующим образом: var app = angular.module('myApp'); . - person lenilsondc; 18.10.2016
comment
Кроме того, это решение не использует $q напрямую, ваша ошибка должна быть чем-то другим, и я тестировал как .config, так и .run, вводимые с константой environment, и это работало нормально. - person lenilsondc; 18.10.2016