Angular JS: импорт данных JSON с помощью $http.get() — работает в контроллере, а не в сервисе — ПОЧЕМУ?

Я пытаюсь импортировать данные JSON в приложение angularJS. Я разделил свое приложение на контроллер и службу импорта, но оба в разных файлах. Я также использую Bower, grunt и yoman (это из-за работы, я не совсем привык к этим, может быть, тоже проблема.)

Странное поведение:

Я хотел получить данные JSON с помощью $http.get() и разрешить их - все в службе, чтобы я мог передать объект данных оттуда главному контроллеру и не должен был разрешать его там. Странно, я не получил никаких данных, они были пусты или не читабельны. Затем я передал обещание, которое мне возвращает механизм $http.get(), и разрешил его в контроллере. Это не то, что я хотел, но теперь это работает... но почему?

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

Буду признателен за каждый намек или идею... Яна

Вот мой код из НЕ рабочей версии, сначала основной модуль с контроллером:

/** Main module of the application. */
(function () {
  'use strict;'
  angular.module('angularRegelwerkApp', [])
    .controller('RegelwerkCtrl', function ($scope, CategoryFactory) {

      $scope.categories = CategoryFactory.getCategories();
      $scope.subcategories = CategoryFactory.getSubCategories();

    }
  );
})();

Сервисная часть:

(function () {
  'use strict';
  var app = angular.module('angularRegelwerkApp')
    .service('CategoryFactory',
    function ($http) {

      var categories = [];
      var subcategories = [];

      $http.get("../mockdata/categories.json").then(function (response) {
        categories = response.data;
      })
      $http.get('../mockdata/subcategories.json').then(function (response) {
        subcategories = response.data;
      })
      return {
        getCategories: function(){
          return categories;
        },
        getSubCategories: function(){
          return subcategories;
        }
      }
    }
  );
})();

Вот мой код из РАБОЧЕЙ версии, сначала основной модуль с контроллером:

/** Main module of the application. */
(function() {
  'use strict;'
  angular.module('angularRegelwerkApp', [])
    .controller('RegelwerkCtrl', function ($scope, CategoryFactory) {

      $scope.categories = [];
      $scope.subcategories = [];

      CategoryFactory.getCategories().then(function(response) {
        $scope.categories = response.data;
      });
      CategoryFactory.getSubCategories().then(function(response) {
        $scope.subcategories = response.data;
      });
    }
  );
}
)();

Сервисная часть:

(function () {
  'use strict';
  var app = angular.module('angularRegelwerkApp')
    .service('CategoryFactory',
    function ($http, $q) {

      var categoryURL = "../mockdata/categories.json";
      var subcategoryURL = '../mockdata/subcategories.json';

      function getSubCategories() {
        return $http.get(subcategoryURL);
      }
      function getCategories() {
        return $http.get(categoryURL);
      }
      return {
        getCategories: getCategories,
        getSubCategories: getSubCategories
      }
    }
  );
})();

person Jana    schedule 17.11.2014    source источник


Ответы (3)


Это разрушает вашу ссылку, поэтому переберите данные с сервера и вставьте их в нужные вам переменные:

  $http.get("../mockdata/categories.json").then(function (response) {
    for(var x = 0; x < response.data.length; x++){
        categories.push(response.data[x]);
    }
  });
person Mathew Berg    schedule 17.11.2014
comment
хорошо... Я хочу попробовать это. Но как перебрать свойства неизвестного объекта и заполнить ими категории? С for (var property in responseData) я получил только увеличивающийся номер индекса, предупреждающий property. И как добавить недвижимость в категории? Данные JSON похожи на список объектов, которые имеют несколько свойств... - person Jana; 17.11.2014
comment
Спасибо! Это действительно легко, мой разум был немного заблокирован, я думаю. И это сработало! очень хорошо. Благодарю вас! - person Jana; 17.11.2014
comment
Еще есть вопрос понимания... почему сработало, когда я разрешил промис в контроллере? Код такой же, как в моем сервисе (до исправления), без всяких циклов, но работал нормально. Ты знаешь почему? Просто для разрешения требуется несколько миллисекунд, и либо передача его контроллеру, либо зацикливание на нем достаточно времени для разрешения? Но почему тогда он не уничтожает ссылку в контроллере? - person Jana; 17.11.2014
comment
Потому что это та же ссылка в контроллере, поскольку вы напрямую изменяете переменные, прикрепленные к объекту области. В вашем сервисе массивы не привязаны к объекту, и поэтому вы уничтожаете их, когда сбрасываете их после http-сообщения. - person Mathew Berg; 17.11.2014

Вызов $http по умолчанию является асинхронным.

Таким образом, в вашей первой версии, когда вы пишете как $scope.categories = CategoryFactory.getCategories();, вы получаете пустые категории, поскольку к тому времени, когда вы получаете доступ к категориям, он может не быть загружен данными ответа.

ваше приложение работает так:

  1. вы загружаете контроллер
  2. Вы звоните в службу
  3. служба вызывает $http
  4. вы пытаетесь получить доступ к категориям (но данные не будут доступны, пока не будет получен ответ с сервера)
  5. $http.then загружает данные в $scope.categories
person Rabi    schedule 17.11.2014
comment
Странно, но в тестовой версии без фреймворка все работало... Итак, если я хочу капсулировать функцию извлечения в сервисе, что вы предлагаете делать? Мне приходит в голову добавить какую-то функцию ожидания, но это выглядит довольно уродливым хакерством... - person Jana; 17.11.2014
comment
правильно - функция ожидания была бы уродливой. Вы можете использовать $watch для переменных области видимости, чтобы увидеть, поступили ли данные с сервера, и действовать соответствующим образом. Но ваша вторая версия чиста и предпочтительнее. - person Rabi; 17.11.2014
comment
Ну, может быть, это достаточно чисто, чтобы работать, но функция не разделена четко, как мне бы хотелось... :-( Я посмотрю, поможет ли здесь $watch, пока не знаю эту функцию. - person Jana; 17.11.2014

Вы храните свои данные в примитивах Angular, и они не обновляются. вместо этого храните все свои данные в объекте, и он должен работать (вам также необходимо обновить контроллер)

(function () {
  'use strict';
  var app = angular.module('angularRegelwerkApp')
    .service('CategoryFactory',
    function ($http) {

      var data = {};

      $http.get("../mockdata/categories.json").then(function (response) {
        data.categories = response.data;
      })
      $http.get('../mockdata/subcategories.json').then(function (response) {
        data.subcategories = response.data;
      })
      return {
        getCategories: function(){
          return data.categories;
        },
        getSubCategories: function(){
          return data.subcategories;
        }
      }
    }
  );
})();
person Simon H    schedule 17.11.2014
comment
Спасибо за предложение, я попробую это и отпишусь, работает ли это! - person Jana; 17.11.2014
comment
Что ж, теперь я получаю Error: $scope.categories is undefined - хотя я, конечно, создал экземпляр $scope.categories и использовал приведенный выше нерабочий код для моего контроллера. О. — Почему? Я не знаю... - person Jana; 17.11.2014
comment
Вы использовали $scope.categories = CategoryFactory.data.categories ? - person Simon H; 17.11.2014
comment
Нет. Поскольку вы возвращаете data.categories в службе, я только что использовал $scope.categories = CategoryFactory.getCategories(), чтобы точно получить свойство категории объекта данных. - person Jana; 17.11.2014