【问题标题】:$scope.$watch, but just for ngChange events?$scope.$watch,但只针对 ngChange 事件?
【发布时间】:2013-07-25 01:14:01
【问题描述】:

我想订阅一个 ngChange 事件,但从代码而不是标记。也就是说,给定一个 $scope 和一个可通过 ngModel 绑定的表达式,我想订阅绑定到该表达式的任何 ngModel 指令对该表达式所做的任何更改。这可能吗?

类似:

$scope.field = "hello";
$scope.onButtonClick = function() {
  $scope.field = "button clicked!";
}

// this callback is only when the user types in an input bound to field
// not when they click the button with ng-click="onButtonClick()"
$scope.$watchNgChange("field", function() { 
  console.log("user caused field to change via a binding");
});

// this callback is called for both ngModel binding changes and onButtonClick.
$scope.$watch("field", function() {
  console.log("field was changed");
});

我不能只使用 $watch,因为它会捕获所有更改,包括从数据库加载数据、ng-click 回调以及从 $watch 回调为其他表达式发起的更改(在这种情况下,如果有任何循环引用,那么很容易让 $watch 回调进入无限循环并在 10 个摘要循环后出错),谁知道还有什么。

【问题讨论】:

    标签: angularjs angularjs-scope


    【解决方案1】:

    首先,任何时候我尝试做这样的事情都被证明是个坏主意 - 我只是在解决我的代码中的设计问题或我的业务逻辑中的逻辑问题。一般来说,代码不应该关心数据是如何改变的,只关心它已经改变了。

    其次,$watch 可以同时给你新旧价值——这对我来说已经足够了。如果旧值不等于新值,我想更新相关的数据模型。如果旧值和新值相等,我想忽略更新。

    最后,您可以考虑在路由中使用 resolve 来消除“数据库加载”,因为完全定位的数据可以传递到您的控制器(假设您返回一个承诺)。

    .

    【讨论】:

    • 我的级联更新依赖图中有循环,$watch 的非确定性使得不可能在所有情况下都正确遍历图,例如确保每个节点只为场景 A 处理一次,但允许在场景 B 中对其进行两次处理。此外,旧的 != new 检查不足以终止在任何情况下的无限 $digest 循环,但最微不足道的用例除外。如果由我决定,我会使用 ngChange 并完成它,但这不取决于我,我正在寻找解决方法。
    • 将此标记为答案 - 因为我开始相信我的想法一开始就不是一个好的想法。感谢您的解决建议。我会调查的。
    【解决方案2】:

    Jeremy,您只是描述了 Angular 中所谓的指令。每次需要接触 DOM 时始终使用指令是最佳实践。这个逻辑不应该存在于控制器甚至服务中。

    指令非常棘手,但有大量的文档。

    访问 docs.angularjs.org/directives

    【讨论】:

      【解决方案3】:

      不要这样做,这听起来像是您试图将 DOM 逻辑(例如,如果用户与 DOM 元素交互)到控制器中。

      如果您阅读 ngChange 指令的源代码,您会发现它需要一个 ngModel 用作视图和控制器之间的桥梁。

      我建议创建模型的副本,并在您的视图中使用 ngModel+ngChange 将该副本用于数据绑定,然后您可以 $watch 该副本并做任何您想做的事情。

      $scope.field = "hello"; //the field you care
      $scope.fieldCopy = $scope.field; //use 'fieldCopy' for databinding
      

      在 html 代码中,您可以有多种方式更改模型字段复制

      <input ngModel="fieldCopy" name='foo' />
      <input ngModel="fieldCopy" name='foo2' />
      

      然后您观察 fieldCopy 以了解与用户交互相关的更改并将更改复制到“field”:

      $scope.$watch("fieldCopy", function() {
        $scope.field = $scope.fieldCopy;
         console.log("user caused field to change via a binding"); 
      });
      

      如果要让 fieldCopy 与 field 保持同步,请添加另一个手表:

      $scope.$watch("field", function() {
        $scope.fieldCopy = $scope.field;
      });
      

      【讨论】:

      • 嗯,关闭,但是如果 $scope.field 从另一个回调更改,那么 $scope.fieldCopy 将不会同步。
      • 在这种情况下,您可以将手表添加到字段并同步 fieldCopy
      • 只有在相关字段有可靠的 angular.equals 时才有可能。否则,将无法阻止无限的 $digest 循环。
      猜你喜欢
      • 2016-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多