Служба Angular, которая инкапсулирует данные веб-службы.

В настоящее время я пишу внешнее приложение с угловым js.

Я использую Restangular для обработки всех запросов REST. Загрузка данных в настоящее время работает идеально.

Я хочу сделать следующее:

Я хочу написать сервис/фабрику/провайдера, который возвращает название каждого языка. Этот вызов нужно сделать только один раз за весь рабочий процесс (маловероятно, что языки, пока пользователь использует приложение).

Итак, я попробовал что-то вроде этого:

'use strict';

angular.module('maroziFrontendApp')
  .service('LanguagesService', function(Restangular) {
    this.languages = Restangular.one('languages').get();
  });

Но когда я введу это в свой контроллер (или преобразователь Restangular Element), я получу только обещание. Затем я должен сделать еще один обратный вызов, и это портит рабочий процесс.

Я также пробовал:

'use strict';

angular.module('maroziFrontendApp')
  .service('LanguagesService', function(Restangular) {
    Restangular.one('languages').get().then(function(languages) {
      this.languages = languages;
    });
  });

Но это возвращает undefined при введении.

Чтобы уточнить:

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

Есть ли простой способ?


person leifg    schedule 27.12.2013    source источник
comment
Resolve - это способ сделать это, какое это имеет отношение к тому, что вы используете это вне контроллера? Сервисы в angular — это синглтоны.   -  person aet    schedule 27.12.2013


Ответы (5)


Вы также можете использовать $object теперь в Restangular, начиная с версии 1.2.0.

Таким образом, ваш код будет:

angular.module('maroziFrontendApp')
  .service('LanguagesService', function(Restangular) {
    this.languages = Restangular.one('languages').get().$object;
  });

Затем в вашем контроллере:

$scope.languages = LanguageService.languages

И в HTML:

<span>{{languages.name}}</span>

Это выглядит намного лучше :)

person mgonto    schedule 31.12.2013

Во второй попытке вы ссылаетесь на this из функции обратного вызова, и поэтому я думаю, что вы получаете undefined. Следующий пример решает эту проблему.

'use strict';

angular.module('maroziFrontendApp')
  .service('LanguagesService', function(Restangular) {
    var self = this;
    Restangular.one('languages').get().then(function(languages) {
      self.languages = languages;
    });
  });

Этот подход по-прежнему проблематичен, поскольку код, который должен использовать LanguagesService, должен каким-то образом узнать, когда он будет доступен.

Возможно, вы захотите отобразить какое-то сообщение «Загрузка» для пользователя, а затем загрузить все необходимые данные, используя связанные обещания в методе module.run(). Когда все данные загружены, вы можете перенаправить пользователя к точке входа приложения.

Другая альтернатива, которую следует учитывать, заключается в том, что если список языков будет одинаковым для всех пользователей вашего приложения, попробуйте создать и включить файл javascript, как в следующем примере, и вам не нужно будет беспокоиться о проблемах с асинхронностью.

angular.module("maroziFrontendApp")
  .value("Languages", function() {
    return {
      "en": "English",
      "fr": "French",
      "es": "Spanish"
    };
  });
person jessegavin    schedule 27.12.2013

Поскольку вызовы AJAX являются асинхронными, невозможно гарантировать загрузку языков до выполнения функции контроллера.

Что бы это ни стоило, обещания Restangular имеют свойство с именем $object. Он заполняется результатом, как только возвращается ответ.

this.languages = Restangular.one('languages').get().$object;
person a better oliver    schedule 27.12.2013

Выполните загрузку данных по другому маршруту, например /loading, после загрузки данных вы можете перенаправить на страницу, где вы хотите иметь возможность мгновенного доступа к данным из службы.

person eddiec    schedule 27.12.2013

Я мог бы придумать неортодоксальное решение, когда вы вручную загружаете свое угловое приложение.

Вы бы сначала запустили свой сервис, а затем загрузились. вы должны удалить директиву ng-app, конечно

var module = angular.module("app",['restangular','ngMockE2E']);

module.factory('LanguagesService', function(Restangular, $q) {
    var service = {};
    service.init = function() {
        var defered = $q.defer();
        Restangular.one('languages').get().then(function(languages) {
            service.languages = languages;
            service.init = undefined;
            defered.resolve();
        });
        return defered.promise;
    }
    return service;
});

//Manual bootstrap
function bootstrap() {
    var $injector = angular.injector(['app']);
    $injector.invoke(function ($rootScope, $compile, $document, LanguagesService) {
        LanguagesService.init().then(function() {
            $compile($document)($rootScope);       
        });

    });
}
bootstrap();

См. http://jsfiddle.net/VtazD/1/.

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

person kfis    schedule 27.12.2013