从 Angular 中的指令监视控制器的属性

Watching a controller's properties from a directive in Angular

本文关键字:控制器 属性 监视 指令 Angular      更新时间:2023-09-26

我正在尝试从链接函数中的关联指令中观察控制器的属性。控制器本身使用控制器 A 设置为$scope上的"窗口"对象;以下是指令定义:

function windowDirective() {
  return {
    transclude: true,
    template: template,
    restrict: 'E',
    controller: WindowCtrl,
    controllerAs: 'window',
    link: function($scope, $element, $attrs, $ctrl) {
      $scope.$watch('window.x', function(newValue, oldValue) {
        // access x here
      });
    }
  };
}

这是WindowCtrl

'use strict';
class WindowCtrl {
  move(x, y) {
    this.x = x;
    this.y = y;
  }
}
module.exports = WindowCtrl;

当我拖动子指令时,move(x, y)被调用 - 它肯定被调用,并且this.xthis.y肯定是在 WindowCtrl 上设置的。此外,如果我console.dir $scope然后move()几次,我可以在 chrome 中打开示波器(因为它是懒惰评估的),并看到确实设置了$scope.window.x$scope.window.y

但是,除了最初检测到window.x未定义之外,我的$scope.$watch实际上从未触发过。不太确定如何进行。我确实搜索并尝试了我找到的所有解决方案,但似乎都没有奏效。

我正在使用 Angular 1.3.16。

注意:对WindowCtrl.move()的访问只能从 Angular 的摘要周期中访问 - 见下文 - 但是使用 $scope.$apply() 可以解决这个问题。我不确定为什么会这样。你能解释一下吗?下面是嵌套在上述指令中的指令。它将在 onDrag 调用该方法,在我的示例中指向window.move(x, y);

function windowHeaderDirective() {
  return {
    transclude: true,
    template: template,
    replace: true,
    require: `^${windowDirective.$name}`,
    scope: {
      enableClose: '=actionClose',
      draggable: '=',
      onDrag: '&'
    },
    bindToController: true,
    link: function($scope, $element, $attrs, $ctrl) {
      $scope.close = $ctrl.close.bind($ctrl);
      let moving = false;
      $element.on('mousemove', function(event) {
        if(!moving) return
        const { x, y } = event;
        $scope.header.onDrag({ x, y });
        // $scope.$apply here will fix this issue, but why? Isn't $element.on within angular's digest cycle??
      });
      $element.on('mousedown', function(event) {
        moving = true;
      });
      $element.on('mouseup', function(event) {
        moving = false
      });
    },
    controller: controller,
    controllerAs: 'header'
  };
}

在$watch中尝试使用如下所示的函数观察器:

$scope.$watch(function() {
  return $scope.window.x
 }, ...

自我回答:

看来,由于我的更新,我自己回答了这个问题,所以;

$element.on似乎实际上并没有处于角消化周期中 - 这对我来说相当令人惊讶,我认为它会。但是,这本质上意味着我的代码可以正常工作 - 只是对控制器上变量的更改并不明显。解决此问题的方法是简单地使用 ng-mousedown et al,或者在$element.on处理程序中使用 $scope.$apply