javascript - AngularJS 指令回调函数计时问题

标签 javascript angularjs angularjs-directive callback

我偶然发现了一个我不明白或不知道如何解决的 Angular 问题。

我想要一个位于 Controller 中的回调函数,一旦某事完成,指令就会调用该回调函数。该指令首先更改一些范围变量并运行回调。然后回调函数继续使用相同的范围变量做一些事情。这似乎令人困惑,因为我想要这个,但考虑到该指令是通用的并且处理许多不同的情况,而回调是一个非常具体的函数。重要的是要注意我不能将此变量作为参数传递,因为其他代码也需要使用此范围变量。

现在进入问题。在执行回调之前,我已经完成了所有工作。似乎在回调中,变量尚未更改。但是,如果设置了超时(在我的示例中为一秒钟),则变量被识别为已更改。为什么它有这种行为?即使在调用回调之前的指令中,它也表明变量实际上已更改。我创建了一个 Codepen 来演示这个问题。它只是将按钮标签从“A”切换到“B”。尽管在控制台日志中您会注意到,当在回调中打印变量时,在我等待之前它是“旧”值。

任何信息都会很棒,谢谢!

注意:我想到的一个想法是将范围变量的副本保存为指令中的局部变量,并将该局部变量作为参数发送给回调,因为回调是目前我唯一关心的函数知道变量的变化并据此采取行动。

代码笔:http://codepen.io/anon/pen/KayaRW

HTML:

<div ng-app="myApp" ng-controller="myCtrl">
   <div ng-test="" button-label="myLabel" callback="cbFunc()">
   </div>
</div>

JS:

angular
   .module('myApp', [])
   .controller('myCtrl', function($scope) {

      $scope.myLabel = "A";

      $scope.cbFunc = function() {
          console.log("myLabel in callback: " + $scope.myLabel);
          setTimeout(function() {
            console.log("myLabel in callback, after 1 sec: " + $scope.myLabel);
            console.log("");
         }, 1000);
      }

   }).directive('ngTest', function() {
      return {
         scope: {
            buttonLabel: '=',
            callback: '&'
         },
         template: function(element, attrs) {
            element.html("<button class=\"btn\" ng-click=\"changeLabel()\">Button Label: {{buttonLabel}}</button>");
         },
         link: function($scope, $element, $attrs) {
            $scope.changeLabel = function() {
               if ($scope.buttonLabel == "A") {
                  $scope.buttonLabel = "B";
               } else {
                  $scope.buttonLabel = "A";
               }
               console.log("myLabel before callback: "+ $scope.buttonLabel);
               $scope.callback();
            }
         }
      }
   });

最佳答案

您有几个选择。我相信您的问题正在发生,因为该指令正在创建一个独立的范围。 我还将指令更改为可读性元素:

1) 不要使用回调,你的 $scope.myLabel 已经双向绑定(bind)。

2) 您可以将超时设置为 0,它似乎仍然有效。我使用了 $timout 服务:

<div ng-app="myApp" ng-controller="myCtrl">
  <ng-test button-label="myLabel" callback="cbFunc()"> </ng-test>
  <p>
 Here is the updated label in the timeout::::: {{updatedLabel}}
  </p>
</div>
angular
  .module('myApp', [])
  .controller('myCtrl', function($scope, $timeout) {
  $scope.myLabel = "A"; //inital value
  $scope.cbFunc = function() {
    $timeout(function() {
    //$scope.myLabel is updated, $timeout is like an $apply but better
    }, 0);
  }
}).directive('ngTest', function() {
  return {
   restrict: 'E',
    scope: {
      buttonLabel: '=',
      callback: '&'
    },
    template: function(element, attrs) {
      element.html("<button class=\"btn\" ng-click=\"changeLabel()\">Button Label: {{buttonLabel}}</button>");
    },
    link: function($scope, $element, $attrs) {
      $scope.changeLabel = function() {
        if ($scope.buttonLabel == "A") {
          $scope.buttonLabel = "B";
        } else {
          $scope.buttonLabel = "A";
        }

        $scope.callback();
      }
    }
  }
});

3) 您的回调可以接受参数,指令会将其传回,您说这不是一个真正的选择。

<div ng-app="myApp" ng-controller="myCtrl">
  <ng-test button-label="myLabel" callback="cbFunc(data)"> </ng-test>
  <p>
 Here is the updated label in the timeout::::: {{updatedLabel}}
  </p>
</div>

angular
  .module('myApp', [])
  .controller('myCtrl', function($scope,$timeout) {
 $scope.myLabel = 'A';

 $scope.cbFunc = function(data){
   $scope.updatedLabel = data;
 }

}).directive('ngTest', function() {
  return {
    restrict: 'E',
    scope: {
      buttonLabel: '=',
      callback: '&'
    },
    template: function(element, attrs) {
      element.html("<button class=\"btn\" ng-click=\"changeLabel()\">Button Label: {{buttonLabel}}</button>");
    },
    link: function($scope, $element, $attrs) {
      $scope.changeLabel = function() {
        if ($scope.buttonLabel == "A") {
          $scope.buttonLabel = "B";
        } else {
          $scope.buttonLabel = "A";
        }

        $scope.callback({data: $scope.buttonLabel});
      }
    }
  }
});

4) $emit 对象在每次更新时备份, Controller 可以监听它。在你的指令中而不是调用回调,调用

$scope.$emit('sudoCallback', $scope.buttonLabel);

在你的 Controller 中而不是你的回调函数

 $scope.$on('sudoCallback', function(event, data) {$scope.updatedLabel = data });

我不喜欢这个选项,因为范围层次结构会导致问题

5) 在 Controller 中为 $scope.myLabel 使用 $watch 并完全摆脱回调。

  $scope.$watch('myLabel', function(newVal){
    $scope.updatedLabel = newVal;
  });

我不喜欢添加一堆 watch ,但它确实有效。

github 上还有一个非常酷的库,它充当消息中心,因此您无需关心范围层次结构,只需订阅和发布即可。 GitHub Angular Message Bus

关于javascript - AngularJS 指令回调函数计时问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41904088/

相关文章:

javascript - 指令采用同一实例的范围

javascript - JWT sha256 哈希与 Internet 草稿示例不匹配

javascript - 将数组添加到数组项中

javascript - 将动态 CSS 样式应用于谷歌地图的标记

javascript - 如何在 jspdf.js 中设置导出表格的字体大小?

angularjs-directive - Jade 中的 Angular 指令

javascript - 检查页面加载时的 Facebook 登录状态

javascript - 无法让简单的 Bootstrap 模式工作

javascript - 无法使用 Angular JS 将 Base 64 图像数据发送到服务器

javascript - 如何在 AngularJS 中打开 .exe 文件?