我已经实现了一个filedrop指令,该指令将文件放在ngModel中。
<filedrop data-ng-model="file"></filedrop>
我在控制器中使用以下代码:
$scope.$watch('file', function(newVal, oldVal) {
if (newVal) {
var reader = new FileReader();
reader.onload = function(event) {
$scope.parseFile(newVal);
};
reader.readAsDataURL(newVal);
}
}, false);
在$ scope.parseFile中我实际上解析了XLSX:
$scope.parseFile = function(file) {
xlsxParser.parse(file).then(function(data) {
console.log("Number of columns", data.datasheet[1].length);
console.log("Number of rows", data.datasheet.length);
$scope.validationErrors = [];
$scope.brand = {
items: []
};
$scope.dataItems = [];
$scope.datasheetValidate(data.datasheet, $scope.brand);
$scope.datasheetData(data.datasheet, $scope.dataItems);
if ($scope.validationErrors.length == 0) $scope.validationErrors.push("Nice work, no validation errors");
//$scope.$apply(function(){});
}, function(err) {
console.log('error', err);
});
}
如您所见,我评论了身体中的//$scope.$apply(function(){});
....
但我需要它才能让我的网页更新范围更改(例如显示validationErrors
)
为什么我需要$scope.$apply
?
答案 0 :(得分:2)
你使用$ scope并不重要。$ watch。当您从$scope.parseFile
回调内部调用reader.onload
时,这无效,这是在Angular领域之外。
$scope.$apply
应该在回调本身中使用:
reader.onload = function(event) {
$scope.$apply(function(){
$scope.parseFile(newVal);
});
};
答案 1 :(得分:0)
$scope.$watch
和$scope.$apply
是互补的。
$scope.$watch
在范围内注册了新的观察者。每当有摘要周期时,监视功能就会运行。
$scope.$apply
触发一个摘要周期 - 也就是说,如果没有任何内容调用$scope.$apply
,则根本不会运行任何观察者。
对于处理用户输入(ng-click
,ng-keydown
等)的内置指令和内置服务($http
,$location
,{{1等等),Angular为你调用$timeout
。但是,每当您处理位于这些内置指令或服务之外的异步代码时,您必须告诉Angular它应该通过自己调用$scope.$watch
来启动新的摘要周期。
如Stewie所述,您应尽量使$apply
调用尽可能接近异步操作;在这种情况下,它意味着在$apply
回调的最顶层使用它。
答案 2 :(得分:0)
如果xlsxParser.parse(file).then不是角度承诺回调方法,我发现这种情况的唯一原因。
正如@Sander所证实的那样,这确实不是一个有角度的承诺,所以这里的选择是继续使用现有的$ scope。$ apply call。