目前,我的应用程序有一个 Controller ,它接收一个 JSON 文件,然后使用“ng-repeat”对它们进行迭代。这一切都很好,但我还有一个需要遍历同一个 JSON 文件的指令。这是一个问题,因为我不能在一页上两次请求相同的 JSON 文件(我也不想这样做,因为它效率低下)。如果我更改其中一个 JSON 文件的文件名,指令和 Controller 都可以请求并遍历 JSON 数据。
我想知道的是:将 Controller 的 JSON 请求形成的数组传递到指令中的最佳方法是什么?当我已经通过 Controller 访问它时,如何将数组传递到我的指令中并遍历它?
Controller
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 的 promise system ,与原始回调相比,这将使您的异步服务更具可组合性。幸运的是,Angular 的 $http
服务已经在后台使用了它们。这是一个服务,它将返回一个解析为 JSON 文件中的数据的 promise ;多次调用该服务不会引起第二个 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 操作;您应该不为它们注入(inject)特定于应用程序的服务。在这种情况下,很容易将 locations
服务简单地注入(inject)指令中,但这会将指令与该服务耦合。
A brief aside on code modularity: a directive’s functions should almost never be responsible for getting or formatting their own data. There’s nothing to stop you from using the $http service from within a directive, but this is almost always the wrong thing to do. Writing a controller to use $http is the right way to do it. A directive already touches a DOM element, which is a very complex object and is difficult to stub out for testing. Adding network I/O to the mix makes your code that much more difficult to understand and that much more difficult to test. In addition, network I/O locks in the way that your directive will get its data – maybe in some other place you’ll want to have this directive receive data from a socket or take in preloaded data. Your directive should either take data in as an attribute through scope.$eval and/or have a controller to handle acquiring and storing the data.
在这种特定情况下,您应该将适当的数据放在 Controller 的范围内,并通过属性与指令共享。
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
指令可以与 any 组位置数据一起使用——该指令不会被硬编码为使用特定的数据集,并且简单地通过将指令包含在 DOM 中来链接指令不会触发随机 HTTP 请求。
关于javascript - 在 Angular 中,如何将 JSON 对象/数组传递给指令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21667613/