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

时间:2021-03-23 15:06:02

I've implemented a filedrop directive that puts the file dropped in ngModel.

我已经实现了一个filedrop指令,该指令将文件放在ngModel中。

<filedrop data-ng-model="file"></filedrop>

I'm using the following code in my controller:

我在我的控制器中使用以下代码:

    $scope.$watch('file', function(newVal, oldVal) {
        if (newVal) {
            var reader = new FileReader();
            reader.onload = function(event) {
                $scope.parseFile(newVal);
            };
            reader.readAsDataURL(newVal);
        }
    }, false);

In $scope.parseFile Im actually parsing the XLSX:

在$ 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);
        });
    }

As you can see, I commented out the //$scope.$apply(function(){}); in the body....

如您所见,我注释掉了// $ scope。$ apply(function(){});在身体里....

BUT, I need it in order to have my webpage updated with the scope changes (e.g. show the validationErrors)

但是,我需要它才能让我的网页更新范围更改(例如显示validationErrors)

How come I need the $scope.$apply?

为什么我需要$ scope。$ apply?

3 个解决方案

#1


2  

It doesn't matter that you're using $scope.$watch. That doesn't help when you're calling $scope.parseFile from inside reader.onload callback, which is outside of Angular realm.

你使用$ scope并不重要。$ watch。当你从reader.onload回调中调用$ scope.parseFile时,这无效,这是在Angular领域之外。

$scope.$apply should be used inside the callback itself:

$ scope。$ apply应该在回调本身内部使用:

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

#2


0  

$scope.$watch and $scope.$apply are complementary.

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

$scope.$watch registers a new watcher on the scope. Whenever there's a digest cycle, the watch function runs.

$ scope。$ watch在范围内注册一个新的观察者。每当有摘要周期时,监视功能就会运行。

$scope.$apply triggers a digest cycle--that is to say, if nothing ever called $scope.$apply, no watchers would ever be run at all.

$ scope。$ apply触发一个摘要周期 - 也就是说,如果什么都没有调用$ scope。$ apply,那么根本就不会运行任何观察者。

For built-in directives that deal with user input (ng-click, ng-keydown, etc.) and built-in services ($http, $location, $timeout, etc.), Angular calls $scope.$watch for you. However, any time you deal with asynchronous code that lives outside of these built-in directives or services, you must tell Angular that it should kick off a new digest cycle by calling $apply yourself.

对于处理用户输入(ng-click,ng-keydown等)和内置服务($ http,$ location,$ timeout等)的内置指令,Angular调用$ scope。$ watch for you 。但是,每当您处理生活在这些内置指令或服务之外的异步代码时,您必须告诉Angular它应该通过自己调用$ apply来启动新的摘要周期。

As mentioned by Stewie, you should try to keep your $apply calls as close to the asynchronous operation as possible; in this case, it means using it at the very top level of the onload callback.

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

#3


0  

The only reason i see this happen if xlsxParser.parse(file).then is not a angular promise callback method.

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

And as confirmed by @Sander this indeed is not a angular promise, so option here is to keep using the existing $scope.$apply call.

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

#1


2  

It doesn't matter that you're using $scope.$watch. That doesn't help when you're calling $scope.parseFile from inside reader.onload callback, which is outside of Angular realm.

你使用$ scope并不重要。$ watch。当你从reader.onload回调中调用$ scope.parseFile时,这无效,这是在Angular领域之外。

$scope.$apply should be used inside the callback itself:

$ scope。$ apply应该在回调本身内部使用:

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

#2


0  

$scope.$watch and $scope.$apply are complementary.

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

$scope.$watch registers a new watcher on the scope. Whenever there's a digest cycle, the watch function runs.

$ scope。$ watch在范围内注册一个新的观察者。每当有摘要周期时,监视功能就会运行。

$scope.$apply triggers a digest cycle--that is to say, if nothing ever called $scope.$apply, no watchers would ever be run at all.

$ scope。$ apply触发一个摘要周期 - 也就是说,如果什么都没有调用$ scope。$ apply,那么根本就不会运行任何观察者。

For built-in directives that deal with user input (ng-click, ng-keydown, etc.) and built-in services ($http, $location, $timeout, etc.), Angular calls $scope.$watch for you. However, any time you deal with asynchronous code that lives outside of these built-in directives or services, you must tell Angular that it should kick off a new digest cycle by calling $apply yourself.

对于处理用户输入(ng-click,ng-keydown等)和内置服务($ http,$ location,$ timeout等)的内置指令,Angular调用$ scope。$ watch for you 。但是,每当您处理生活在这些内置指令或服务之外的异步代码时,您必须告诉Angular它应该通过自己调用$ apply来启动新的摘要周期。

As mentioned by Stewie, you should try to keep your $apply calls as close to the asynchronous operation as possible; in this case, it means using it at the very top level of the onload callback.

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

#3


0  

The only reason i see this happen if xlsxParser.parse(file).then is not a angular promise callback method.

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

And as confirmed by @Sander this indeed is not a angular promise, so option here is to keep using the existing $scope.$apply call.

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