当前,我的应用程序具有一个控制器,该控制器接收一个JSON文件,然后使用“ ng- repeat”对其进行迭代。这一切都很好,但是我还有一条指令需要遍历同一JSON文件。这造成了一个问题,因为我无法在一页上两次请求相同的JSON文件(我也不想这样做,因为它效率不高)。如果更改一个JSON文件之一的文件名,指令和控制器都可以请求并遍历JSON数据。
我想知道的是:将由控制器的JSON请求形成的数组传递到指令中的最佳方法是什么?通过控制器访问数组后,如何将其传递到指令中并进行迭代?
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系统,与原始回调相比,这将使您的异步服务更具可组合性。幸运的是,Angular的$http服务已经在后台使用它们。这是一项服务,该服务将返回一个对JSON文件中的数据进行解析的Promise;多次调用服务不会导致第二个HTTP请求。
$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服务简单地注入到指令中,但这会将指令耦合到该服务。
locations
除了代码模块化之外,还简要介绍了:指令的功能几乎永远不应该负责获取或格式化自己的数据。没有什么可以阻止您从指令中使用$ http服务,但这几乎总是错误的做法。编写使用$ http的控制器是正确的方法。指令已经接触到DOM元素,这是一个非常复杂的对象,很难进行测试。将网络I / O添加到组合中会使您的代码更难以理解,也更加难以测试。此外,网络I / O锁定指令获取数据的方式- 也许在其他地方,您可能希望该指令从套接字接收数据或获取预加载的数据。您的指令应通过范围将数据作为属性。 - 编写AngularJS指令的80/20指南
除了代码模块化之外,还简要介绍了:指令的功能几乎永远不应该负责获取或格式化自己的数据。没有什么可以阻止您从指令中使用$ http服务,但这几乎总是错误的做法。编写使用$ http的控制器是正确的方法。指令已经接触到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请求。
map