В Angular, как передать объект/массив JSON в директиву?



В настоящее время в моем приложении есть контроллер, который принимает файл JSON, а затем повторяет их с помощью "ng-repeat". Все это отлично работает, но у меня также есть директива, которая должна повторяться через тот же файл JSON. Это создает проблему, поскольку я не могу запросить один и тот же файл JSON дважды на одной странице (и я бы не хотел, потому что это было бы неэффективно). Как директива, так и запрос контроллера и повторение данных JSON просто отлично, если я изменю имя файла одного из JSON файлы.



что мне интересно: каков наилучший способ передачи массива, сформированного из запроса JSON моего контроллера в директиву? Как я могу передать массив в свою директиву и выполнить итерацию, когда я уже получил доступ к нему через свой контроллер?



контроллер



appControllers.controller('dummyCtrl', function ($scope, $http) {
$http.get('locations/locations.json').success(function(data) {
$scope.locations = data;
});
});


HTML



<ul class="list">
<li ng-repeat="location in locations">
<a href="#">{{location.id}}. {{location.name}}</a>
</li>
</ul>
<map></map> //executes a js library


директива (работает, когда я использую имя файла помимо местоположения.json, так как я уже просил его один раз



.directive('map', function($http) {
return {
restrict: 'E',
replace: true,
template: '<div></div>',
link: function(scope, element, attrs) {

$http.get('locations/locations.json').success(function(data) {
angular.forEach(data.locations, function(location, key){
//do something
});
});
753   3  

3 ответов:

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


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

Я бы лично рекомендовал обнять AngularJS обещать система, что сделает ваши асинхронные службы более составными по сравнению с необработанными обратными вызовами. К счастью, угловой $http сервис уже использует их под капотом. Вот служба, которая вернет обещание, которое разрешает данные из файла JSON; вызов службы более одного раза не вызовет второго HTTP-запроса.

app.factory('locations', function($http) {
  var promise = null;

  return function() {
    if (promise) {
      // If we've already asked for this data once,
      // return the promise that already exists.
      return promise;
    } else {
      promise = $http.get('locations/locations.json');
      return promise;
    }
  };
});

что касается получения данных в вашей директиве, важно помнить, что директивы предназначены для абстрактного обобщения DOM манипуляции; вы должны не вводишь их с применением конкретных услуг. В этом случае было бы заманчиво просто ввести locations сервис в директиву, но это связывает директиву с этой службой.

коротко о модульности кода: функции директивы почти никогда не должны отвечать за получение или форматирование своих собственных данных. Ничто не мешает вам использовать службу $http из директивы, но это почти всегда неправильно. Написание контроллера для использования $http-это правильный способ сделать это. Директива уже касается элемента DOM, который является очень сложным объектом и трудно заглушить для тестирования. Добавление сетевого ввода-вывода в микс делает ваш код гораздо более сложным для понимания и гораздо более сложным для тестирования. Кроме того, сетевой ввод-вывод блокируется таким образом, что ваша директива будет получать свои данные – возможно, в каком-то другом месте вы захотите, чтобы эта директива получала данные из сокета или принимать предварительно загруженные данные. Ваша директива должна либо принимать данные в качестве атрибута через область видимости.$eval и / или иметь контроллер для обработки получения и хранения данных.

-руководство 80/20 по написанию директив AngularJS

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

app.controller('SomeController', function($scope, locations) {
  locations().success(function(data) {
    $scope.locations = data;
  });
});
<ul class="list">
   <li ng-repeat="location in locations">
      <a href="#">{{location.id}}. {{location.name}}</a>
   </li>
</ul>
<map locations='locations'></map>
app.directive('map', function() {
  return {
    restrict: 'E',
    replace: true,
    template: '<div></div>',
    scope: {
      // creates a scope variable in your directive
      // called `locations` bound to whatever was passed
      // in via the `locations` attribute in the DOM
      locations: '=locations'
    },
    link: function(scope, element, attrs) {
      scope.$watch('locations', function(locations) {
        angular.forEach(locations, function(location, key) {
          // do something
        });
      });
    }
  };
});

в этом Кстати, о

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

.controller('MyController', ['$scope', '$http', function($scope, $http) {
  $http.get('locations/locations.json').success(function(data) {
      $scope.locations = data;
  });
}

затем в вашем HTML (где вы вызываете директиву).
Примечание:locations - это ссылка на контроллерах $scope.locations.

<div my-directive location-data="locations"></div>

и, наконец, в вашей директивы

...
scope: {
  locationData: '=locationData'
},
controller: ['$scope', function($scope){
  // And here you can access your data
  $scope.locationData
}]
...

Это просто контур, чтобы указать вам в правильном направлении, так что это неполный и не проверенный.

что вам нужно, это правильно сервис:

.factory('DataLayer', ['$http',

    function($http) {

        var factory = {};
        var locations;

        factory.getLocations = function(success) {
            if(locations){
                success(locations);
                return;
            }
            $http.get('locations/locations.json').success(function(data) {
                locations = data;
                success(locations);
            });
        };

        return factory;
    }
]);

The locations будет кэшироваться в сервисе, который работал как одноэлементная модель. Это правильный способ извлечения данных.

используйте эту услугу DataLayer в вашем контроллере и директиве все в порядке следующим образом:

appControllers.controller('dummyCtrl', function ($scope, DataLayer) {
    DataLayer.getLocations(function(data){
        $scope.locations = data;
    });
});

.directive('map', function(DataLayer) {
    return {
        restrict: 'E',
        replace: true,
        template: '<div></div>',
        link: function(scope, element, attrs) {

            DataLayer.getLocations(function(data) {
                angular.forEach(data, function(location, key){
                    //do something
                });
            });
        }
    };
});

Comments

    Ничего не найдено.