我目前有一个AngularJS控制器,它基本上是通过$http.get()调用异步获取一些
JSON,然后将获得的数据链接到某个范围变量.
控制器代码的恢复版本:
mapsControllers.controller('interactionsController',['$http',function($http) { var ctrlModel = this; $http.get("data/interactionsPages.json"). success(function(data) { ctrlModel.sidebar = {}; ctrlModel.sidebar.pages = data; }). error(function() {...}); }]);
然后,我有一个自定义指令,通过HTML元素接收相同的范围变量.
指令代码的恢复版本:
mapsDirectives.directive('sidebar',function() { return { restrict : 'E',scope : { pages : '@' },controller : function($scope) { $scope.firstPage = 0; $scope.lastPage = $scope.pages.length - 1; $scope.activePage = 0; //... },link : function(scope) { console.log(scope.pages); },templateURL : 'sidebar.html' } });
HTML的恢复版本:
<body> <div ng-controller='interactionsController as interactionsCtrl'> <mm-sidebar pages='{{interactionsCtrl.ctrlModel.sidebar.pages}}'> </mm-sidebar> </div> </body>
问题是,因为$http.get()是异步的,所以指令被初始化很严重(例如:$scope.pages.length – 1未定义).
我找不到任何可以解决这个问题的方法,尽管有一些解决方案似乎可以解决这个问题.也就是说,我试图观察变量,只在检测到变化后初始化变量,正如许多其他帖子所建议的那样.为了测试,我使用了类似的东西:
//... inside the directive's return{ } link: function() { scope.$watch('pages',function(pages){ if(pages) console.log(pages); }); }
我已经测试了它,并且$watch函数没有被多次调用(记录的值未定义),我认为这意味着它没有检测到变量值的变化.但是,我确认价值正在改变.
那么,这里的问题是什么?
解决方法
在控制器中移动侧边栏对象的声明,并将范围绑定更改为=.
mapsDirectives.controller("interactionsController",["$http","$timeout",function($http,$timeout) { var ctrlModel = this; ctrlModel.sidebar = { pages: [] }; /* $http.get("data/interactionsPages.json"). success(function(data) { //ctrlModel.sidebar = {}; ctrlModel.sidebar.pages = data; }). error(function() {}); */ $timeout(function() { //ctrlModel.sidebar = {}; ctrlModel.sidebar.pages = ["one","two"]; },2000); } ]); mapsDirectives.directive('mmSidebar',[function() { return { restrict: 'E',scope: { pages: '=' },controller: function() {},link: function(scope,element,attrs,ctrl) { scope.$watch("pages",function(val) { scope.firstPage = 0; scope.lastPage = scope.pages.length - 1; scope.activePage = 0; }); },templateUrl: 'sidebar.html' }; }]);
<mm-sidebar pages='interactionsCtrl.sidebar.pages'> </mm-sidebar>