【问题标题】:Using $scope.$watch and still need $scope.$apply?使用 $scope.$watch 仍然需要 $scope.$apply?
【发布时间】:2014-02-14 09:03:12
【问题描述】:

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

【问题讨论】:

  • 如果xlsxParser.parse(file).then 不是角度承诺回调方法,我看到这种情况发生的唯一原因。
  • 你说得对。它使用 jQuery 承诺。可能需要重写借来的代码或接受我必须明确调用 apply 的事实:-(
  • 很好,将其添加为答案,以便可以将问题标记为已回答。

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


【解决方案1】:

使用 $scope.$watch 并不重要。当您从 Angular 领域之外的 reader.onload 回调内部调用 $scope.parseFile 时,这无济于事。

$scope.$apply 应该在回调内部使用:

reader.onload = function(event) {
  $scope.$apply(function(){
    $scope.parseFile(newVal);
  });
};

【讨论】:

  • 我试过这个,但它不起作用..可能是因为 Chandermani 提到的评论。他是对的,我可能需要重写,它使用 jQuery 承诺。猜猜当你试图重用其他人的代码时会发生这种情况。
【解决方案2】:

$scope.$watch$scope.$apply 是互补的。

$scope.$watch 在作用域上注册一个新的观察者。每当有一个摘要循环时,watch 函数就会运行。

$scope.$apply 触发一个摘要循环——也就是说,如果没有调用 $scope.$apply,则根本不会运行任何观察者。

对于处理用户输入的内置指令(ng-clickng-keydown 等)和内置服务($http$location$timeout 等),Angular 调用 @ 987654331@为您服务。但是,任何时候你处理这些内置指令或服务之外的异步代码时,你必须告诉 Angular 它应该自己调用$apply 来启动一个新的摘要循环。

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 我重写了代码根本不使用承诺,而是使用回调,但问题仍然存在:-(
    • 你写回调不能解决问题,回调仍然需要包裹在$scope.$apply中才能切换到angularjs上下文。
    • 你知道为什么吗?我不介意把“申请”留在那里,但我一直在想为什么......我很想知道
    猜你喜欢
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-14
    • 1970-01-01
    • 2015-12-08
    • 1970-01-01
    • 2016-02-21
    相关资源
    最近更新 更多