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

Javascript 在Angular中,如何将JSON对象/数组传递到指令中?,javascript,json,angularjs,angularjs-directive,angularjs-ng-repeat,Javascript,Json,Angularjs,Angularjs Directive,Angularjs Ng Repeat,目前,我的应用程序有一个控制器,它接收一个JSON文件,然后使用“ng repeat”对它们进行迭代。这一切都很好,但我还有一个指令需要遍历同一个JSON文件。这是一个问题,因为我不能在一个页面上两次请求同一个JSON文件(我也不想这样做,因为这样会效率低下)。如果我更改其中一个JSON文件的文件名,指令和控制器都会请求并迭代JSON数据 我想知道的是:将控制器的JSON请求形成的数组传递到指令中的最佳方式是什么?当我已经通过控制器访问数组时,如何将数组传递到指令中并进行迭代 控制器 appCo

目前,我的应用程序有一个控制器,它接收一个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
//执行js库
指令(在我使用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
   });
});
指令('map',函数($http){
返回{
限制:'E',
替换:正确,
模板:“”,
链接:函数(范围、元素、属性){
$http.get('locations/locations.json').success(函数(数据){
角度.forEach(数据.位置,功能(位置,键){
//做点什么
});
});

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

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

这只是一个为您指明正确方向的大纲,因此它不完整且未经测试。

您需要的是正确的服务:

.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;
    }
]);
位置
将缓存在作为单例模型工作的服务中。这是获取数据的正确方法

在控制器中使用此服务
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
                });
            });
        }
    };
});
appControllers.controller('dummyCtrl',函数($scope,DataLayer){
DataLayer.getLocations(函数(数据){
$scope.locations=数据;
});
});
.directive('map',函数(数据层){
返回{
限制:'E',
替换:正确,
模板:“”,
链接:函数(范围、元素、属性){
DataLayer.getLocations(函数(数据){
角度.forEach(数据、功能(位置、键){
//做点什么
});
});
}
};
});

如果你想遵循所有的“最佳实践”,我建议你做几件事,其中一些会在这个问题的其他答案和评论中提到


首先,虽然它对您提出的特定问题没有太大影响,但您确实提到了效率,在应用程序中处理共享数据的最佳方法是将其分解到服务中

我个人建议采用AngularJS,这将使您的异步服务比原始回调更具可组合性。幸运的是,Angular的
$http
服务已经在幕后使用了它们。这里有一个服务将返回解析JSON文件中数据的承诺;在将不会导致第二个HTTP请求

app.factory('locations',函数($http){
var-promise=null;
返回函数(){
如果(承诺){
//如果我们已经问过一次这个数据,
//返回已经存在的承诺。
回报承诺;
}否则{
promise=$http.get('locations/locations.json');
回报承诺;
}
};
});

至于将数据输入到指令中,重要的是要记住,指令是为抽象通用DOM操作而设计的;您不应该将它们注入特定于应用程序的服务。在这种情况下,只需将
locations
服务注入指令中就很有诱惑力,但这会将指令与那项服务

关于代码模块化的简短旁白:指令的函数几乎不应该负责获取或格式化它们自己的数据。没有什么可以阻止您在指令中使用$http服务,但这几乎总是错误的。编写控制器以使用$http是正确的方法。指令lready涉及一个DOM元素,它是一个非常复杂的对象,很难进行测试。将网络I/O添加到混合中会使您的代码更难理解,也更难测试。此外,网络I/O会以指令获取数据的方式锁定—可能在您需要的其他地方t使此指令从套接字接收数据或接收预加载的数据。您的指令应通过scope.$eval将数据作为属性接收,和/或使用控制器处理数据的获取和存储

-

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

app.controller('SomeController',函数($scope,locations){
位置().成功(函数(数据){
$scope.locations=数据;
});
});
app.directive('map',function(){
返回{
限制:'E',
替换:正确,
模板:“”,
范围:{
//在指令中创建范围变量
//被称为绑定到所传递内容的“位置”
//在中,通过DOM中的“locations”属性
位置:'=位置'
},
链接:函数(范围、元素、属性){
范围:$watch('位置'),功能(位置){
角速度(位置、功能(l
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
                });
            });
        }
    };
});