Ome*_*len 52 javascript json angularjs angularjs-directive angularjs-ng-repeat
目前,我的应用程序有一个控制器,它接收一个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;
});
});
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
指令(当我使用除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
});
});
Run Code Online (Sandbox Code Playgroud)
Mic*_*ley 91
如果你想要遵循所有"最佳实践",我会推荐一些事情,其中一些内容会在其他答案和评论中提及.
首先,虽然它对您提出的具体问题没有太大的影响,但您确实提到了效率,在您的应用程序中处理共享数据的最佳方法是将其分解为服务.
我个人建议使用AngularJS的promise系统,这将使你的异步服务与原始回调相比更具组合性.幸运的是,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;
}
};
});
Run Code Online (Sandbox Code Playgroud)
至于将数据导入到您的指令中,重要的是要记住指令旨在抽象泛型DOM操作; 你应该不与特定的应用服务,将它们注入.在这种情况下,将locations服务简单地注入指令是很诱人的,但这会将指令耦合到该服务.
关于代码模块化的简要说明:指令的函数几乎不应该负责获取或格式化自己的数据.没有什么可以阻止你在指令中使用$ http服务,但这几乎总是错误的做法.编写控制器以使用$ http是正确的方法.指令已经触及DOM元素,这是一个非常复杂的对象,很难用于测试.在混合中添加网络I/O会使您的代码更难以理解并且更难以测试.此外,网络I/O以您的指令获取其数据的方式锁定 - 可能在其他地方您希望此指令从套接字接收数据或接收预加载的数据.您的指令应该通过作用域将数据作为属性.$ eval和/或有一个控制器来处理获取和存储数据.
在这种特定情况下,您应该将适当的数据放在控制器的范围内,并通过属性与指令共享.
app.controller('SomeController', function($scope, locations) {
locations().success(function(data) {
$scope.locations = data;
});
});
Run Code Online (Sandbox Code Playgroud)
<ul class="list">
<li ng-repeat="location in locations">
<a href="#">{{location.id}}. {{location.name}}</a>
</li>
</ul>
<map locations='locations'></map>
Run Code Online (Sandbox Code Playgroud)
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
});
});
}
};
});
Run Code Online (Sandbox Code Playgroud)
通过这种方式,该map指令可以与任何位置数据集一起使用- 该指令不是硬编码的,以使用特定的数据集,只需通过将指令包含在DOM中来链接指令就不会触发随机的HTTP请求.
Ind*_*dex 11
如你所说,你不需要两次请求文件.将它从您的控制器传递到您的指令.假设您在控制器范围内使用该指令:
.controller('MyController', ['$scope', '$http', function($scope, $http) {
$http.get('locations/locations.json').success(function(data) {
$scope.locations = data;
});
}
Run Code Online (Sandbox Code Playgroud)
然后在你的HTML中(你在那里调用指令).
注意: locations是对控制器的引用$scope.locations.
<div my-directive location-data="locations"></div>
Run Code Online (Sandbox Code Playgroud)
最后在你的指令中
...
scope: {
locationData: '=locationData'
},
controller: ['$scope', function($scope){
// And here you can access your data
$scope.locationData
}]
...
Run Code Online (Sandbox Code Playgroud)
这只是一个指向正确方向的大纲,因此它不完整且未经过测试.
您需要的是正确的服务:
.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;
}
]);
Run Code Online (Sandbox Code Playgroud)
该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
});
});
}
};
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
100183 次 |
| 最近记录: |