Приложение AngularJS: загружайте данные из JSON один раз и используйте их в нескольких контроллерах.

Я работаю над мобильным приложением, используя AngularJS в качестве основы, в настоящее время у меня есть структура, подобная этой:

app.config(['$routeProvider', function($routeProvider) {
    $routeProvider
        .when('/', {
            templateUrl : 'pages/home.html',
            controller  : 'homeCtrl'
        })

        .when('/one', {
            templateUrl : 'pages/one.html',
            controller  : 'oneCtrl'
        })

        .when('/two', {
            templateUrl : 'pages/two.html',
            controller  : 'twoCtrl'
        });
}]);

app.controller('homeCtrl', ['$scope', function($scope) {

}]);

app.controller('oneCtrl', ['$scope', function($scope) {

}]);

app.controller('twoCtrl', ['$scope', function($scope) {

}]);

А затем я показываю содержимое с помощью ng-view:

<div class="ng-view></div>

Все работает хорошо, но мне нужно загрузить данные из файла JSON, чтобы заполнить все содержимое приложения. Я хочу сделать вызов AJAX только один раз, а затем передать данные через все мои разные контроллеры. В моей первой попытке я подумал создать службу с $http.get() внутри нее и включить ее в каждый контроллер, но это не работает, потому что каждый раз, когда я внедряю и использую службу, она делает другой запрос ajax. Поскольку я новичок в использовании angular, мне интересно, как лучше всего или более «угловым способом» добиться этого, не испортив его.

Редактировать: я добавляю код службы, который представляет собой простой $http.get запрос:

app.service('Data', ['$http', function($http) {
    this.get = function() {
        $http.get('data.json')
        .success(function(result) {
            return result;
        })
    }
});

person Didier    schedule 11.06.2015    source источник
comment
Ваш сервис отсутствует в примере кода, который было бы очень полезно увидеть здесь.   -  person seanhodges    schedule 11.06.2015
comment
@Didier Я бы посоветовал вам разделить файлы кода на разные контроллеры и использовать службу для получения этих данных. см. мой ответ для сервисного кода   -  person Gurbakhshish Singh    schedule 11.06.2015


Ответы (2)


Попробуйте это, чтобы получить данные JSON из ссылки GET:

(function (app) {
    'use strict';

    app.factory('myService', MyService);

    MyService.$inject = ['$q', '$http'];

    function MyService($q, $http) {
        var data;

        var service = {
            getData: getData
        };

        return service;

        //////////////////////////////////////

        function getData(refresh) {
            if (refresh || !data) {
                return $http.get('your_source').then(function(data){
                    this.data = data;
                    return data;
                })
            }
            else {
                var deferrer = $q.defer();
                deferrer.resolve(data);
                return deferrer.promise;
            }
        }
    }

}(angular.module('app')));

Теперь вы можете добавить эту зависимость в свой файл контроллера и использовать:

myService.getData().then(function(data){
    //use data here 
}, function(err){
    //Handle error here
});
person Gurbakhshish Singh    schedule 11.06.2015
comment
Это сработало как шарм, я думал, что могу решить эту проблему несколькими способами, но использование одноэлементного шаблона никогда не приходило мне в голову. Спасибо! - person Didier; 11.06.2015
comment
Я получаю this is undefined для строки this.data = data; , и если я ее удаляю, то запрос GET выполняется несколько раз. Есть идеи? - person bjesus; 29.08.2015
comment
инициализация нового промиса не требуется, так как $http возвращает промис, вместо этого вы можете вернуть ссылку на промис, ответ правильный, но он может быть более кратким - person Dane Macaulay; 13.11.2015

Инициализируйте промис один раз и верните ссылку на него:

Нет необходимости инициализировать другое обещание. $http возвращает один.

Просто добавьте .then() к своему обещанию, чтобы изменить результат.

angular.module('app', [])
  .service('service', function($http){
    this.promise = null;
    function makeRequest() {
         return $http.get('http://jsonplaceholder.typicode.com/posts/1')
             .then(function(resp){
                  return resp.data;
             });
    }
    this.getPromise = function(update){
      if (update || !this.promise) {
         this.promise = makeRequest();
      }
      return this.promise;      
    }
  })

Пример Codepen

Изменить: вместо этого вы можете использовать кеш $http. Он может достичь тех же результатов. Из документации:

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

person Dane Macaulay    schedule 11.06.2015
comment
Это отлично работает, если вам не нужно изменять/обрабатывать данные, возвращаемые ответом get, поскольку это возвращает само обещание вместо данных, к сожалению, это не мой случай. Спасибо за ответ. - person Didier; 11.06.2015
comment
пример можно расширить, чтобы сделать это :) - person Dane Macaulay; 11.06.2015
comment
Да, его можно расширить, действительно, это очень хороший ответ, единственная причина, по которой я не выбрал его в качестве принятого ответа, заключалась в том, что ответ haw-i- уже учитывал тот факт, что данные можно обрабатывать. Большое спасибо, еще раз. - person Didier; 15.06.2015
comment
Я проголосовал за этот ответ, потому что @DaneMacaulay сделал все возможное и продемонстрировал идею на примере кода. Очень чистый и эффективный подход. - person Rod Hartzell; 12.11.2015
comment
Работал отлично! Да, вы можете изменить код для форматирования данных. Просто введите return resp.data; ваш звонок вот так return myFormatting(resp.data);. AJAX выполняется только один раз, а данные кэшируются и повторно используются во всех контроллерах. - person Nelson Rodriguez; 03.05.2016