【发布时间】:2014-05-31 09:19:52
【问题描述】:
我有一个奇怪的错误,我无法弄清楚。我最近将我的 Angular 应用程序重构为更“有角度的”。其中一部分是将窗口调整大小事件处理程序从指令中移出,并将其放入 .run 块中,它可以将 Angular 事件广播到整个应用程序。
那部分似乎工作正常。它监视窗口和事件正确传播。但是,当我从 $on 监听器调用我的模型操作代码时,数据绑定似乎没有触发。
.controller('channelListController', function ($scope, $rootScope, $http, $filter){
$http.get('api/v1/channels').success(function(data){
$scope.baseChannels = data;
filterChannelData($scope.filter);
//call manually since initial window resize occurs before async return
splitChannelData($rootScope.windowAttr.columns);
});
//*************
//this part doesn't trigger databinding update
//*************
$scope.$on('columnChange', function(){
//window resize requires changing column number
console.log('change detected');
splitChannelData($rootScope.windowAttr.columns);
});
//*************
//but this does
//*************
$scope.$watch('filter', function(newVal){
//the filters are changed
filterChannelData(newVal);
//re-run split for new data
splitChannelData($rootScope.windowAttr.columns);
}, true);
function filterChannelData(filter){
if(filter){
$scope.filteredChannels = $filter('looseCreatorComparator')($scope.baseChannels, filter.creators);
$scope.filteredChannels = $filter('looseTagComparator')($scope.filteredChannels, filter.tags);
} else {
$scope.filteredChannels = $scope.baseChannels;
}
}
function splitChannelData(columns){
if(columns){
$scope.splitChannels = [];
for(var rep=0;rep<columns;rep++){
$scope.splitChannels.push([]);
}
_.forEach($scope.filteredChannels, function(channel, index){
$scope.splitChannels[index % columns].push(channel);
});
}
}
});
因此,当我更改过滤器输入字段的内容时,$watch 会捕获它,运行我的过滤器,然后触发 splitChannelData。后者将我的数据集重构为一组单独的数组以供显示。该视图数据绑定到 $scope.splitChannels。这很好用。
但是,当广播 'columnChange' 事件被 $on 捕获时,splitChannelData 函数会触发,正确重构 $scope.splitChannels 但视图不会刷新以反映更改。
此外,如果我随后对过滤器输入字段进行另一项更改并触发 $watch 处理程序,它会正确更新视图,包括 $on 所做但未更新到早点查看。
WUT。
那么,谁能告诉我为什么从 $scope.$watch 调用 splitDataChannel 可以使数据绑定正常工作,但由 $scope.$on 触发的同一个调用却不能?
编辑: 我刚刚解决了这个错误,但仍然不明白为什么这个解决方案是必要的。我仍然希望得到反馈。
我向 $on 处理程序添加了 $apply 调用:
$scope.$on('columnChange', function(){
//window resize requires changing column number
console.log('change detected');
splitChannelData($rootScope.windowAttr.columns);
//added this
$scope.$apply();
});
为什么 $watch 会触发数据绑定更新,而 $on 不会,而拿铁咖啡需要手动调用 $apply?
【问题讨论】:
-
$scope.$apply();是必要的,因为该事件来自 Angular“世界”之外,因此您需要让应用知道该事件发生了。 -
好的,我知道“外部”事件需要对其调用 $apply 但我很困惑为什么在我的控制器内部调用方法并操作 $scope 不会“强制”代码在 Angular 世界中执行。究竟是什么定义了那个世界的边界?
标签: javascript angularjs data-binding