将异步获取的数据传递给指令
Passing asynchronously obtained data to a directive
我目前有一个 AngularJS controller
基本上是通过 $http.get()
调用异步获取一些 JSON
,然后将获取的数据链接到某个范围变量。
恢复版controller
代码:
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() {...});
}]);
然后,我有一个自定义 directive
,它通过 HTML
元素接收那些相同的范围变量。
恢复版directive
代码:
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 函数只被调用了一次(记录的值为 undefined
),我认为这意味着它没有检测到变量值。但是,我确认该值正在更改。
那么,这里的问题是什么?
在控制器中移动 sidebar
对象的声明并将范围绑定更改为 =
。
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>
问题似乎出在您的 html 标记上。
在您的控制器中,您已指定 ctrlModel
等于 this
。
在您的 html 标记中,您已声明相同的 this
被命名为 interactionsController
。
所以将 ctrlModel
添加到 interactionsController
是不正确的。
<body>
<div ng-controller='interactionsController as interactionsCtrl'>
<!-- remove this -->
<mm-sidebar pages='{{interactionsCtrl.ctrlModel.sidebar.pages}}'>
<!-- replace with this -->
<mm-sidebar pages='{{interactionsCtrl.sidebar.pages}}'>
</mm-sidebar>
</div>
</body>
我目前有一个 AngularJS controller
基本上是通过 $http.get()
调用异步获取一些 JSON
,然后将获取的数据链接到某个范围变量。
恢复版controller
代码:
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() {...});
}]);
然后,我有一个自定义 directive
,它通过 HTML
元素接收那些相同的范围变量。
恢复版directive
代码:
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 函数只被调用了一次(记录的值为 undefined
),我认为这意味着它没有检测到变量值。但是,我确认该值正在更改。
那么,这里的问题是什么?
在控制器中移动 sidebar
对象的声明并将范围绑定更改为 =
。
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>
问题似乎出在您的 html 标记上。
在您的控制器中,您已指定 ctrlModel
等于 this
。
在您的 html 标记中,您已声明相同的 this
被命名为 interactionsController
。
所以将 ctrlModel
添加到 interactionsController
是不正确的。
<body>
<div ng-controller='interactionsController as interactionsCtrl'>
<!-- remove this -->
<mm-sidebar pages='{{interactionsCtrl.ctrlModel.sidebar.pages}}'>
<!-- replace with this -->
<mm-sidebar pages='{{interactionsCtrl.sidebar.pages}}'>
</mm-sidebar>
</div>
</body>