AngularJS:使用$ scope。$ watch并且仍然需要$ scope。$ apply?

时间:2014-02-14 09:03:12

标签: javascript angularjs javascript-events angularjs-directive angularjs-scope

我已经实现了一个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

3 个答案:

答案 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-clickng-keydown等)的内置指令和内置服务($http$location,{{1等等),Angular为你调用$timeout。但是,每当您处理位于这些内置指令或服务之外的异步代码时,您必须告诉Angular它应该通过自己调用$scope.$watch来启动新的摘要周期。

如Stewie所述,您应尽量使$apply调用尽可能接近异步操作;在这种情况下,它意味着在$apply回调的最顶层使用它。

答案 2 :(得分:0)

如果xlsxParser.parse(file).then不是角度承诺回调方法,我发现这种情况的唯一原因。

正如@Sander所证实的那样,这确实不是一个有角度的承诺,所以这里的选择是继续使用现有的$ scope。$ apply call。