在Angular中,如何将JSON对象/数组传递给指令?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (46)

目前,我的应用程序有一个控制器,它接受一个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

指令(当我使用除locations.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
   });
});
提问于
用户回答回答于

如果你想遵循所有的“最佳实践”,我会推荐几件事情,其中​​一些在其他回答和这个问题的评论中被触及。

首先,虽然它对所问的具体问题没有太多影响,但确实提到了效率,处理应用程序中的共享数据的最佳方式是将其分解为服务。

我个人会建议采用AngularJS的诺言系统,这将使异步服务与原始回调相比更加可组合。幸运的是,Angular的$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元素,DOM元素是一个非常复杂的对象,并且很难用于测试。将网络I / O添加到组合中会使代码更加难以理解,而且测试起来更加困难。另外,网络I / O会以您的指令获取数据的方式锁定 - 可能在其他地方希望使用此指令从套接字接收数据或采用预加载的数据。指令应该通过范围将数据作为属性。 - 编写AngularJS指令的80/20指南

在这种特定情况下,应该将适当的数据放在控制器的作用域上,并通过属性与指令共享。

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
        });
      });
    }
  };
});

通过这种方式,map指令可以与任何一组位置数据一起使用 - 该指令不是硬编码以使用特定的一组数据,并且通过将指令包括在DOM中简单地链接该指令将不会触发随机的HTTP请求。

用户回答回答于

正如你所说,你不需要两次请求文件。将它从控制器传递到您的指令。假设你在控制器的范围内使用指令:

.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
}]
...

这只是一个提示指向正确方向的轮廓,因此它不完整并未经过测试。

扫码关注云+社区

领取腾讯云代金券