Angular.js: 在为隔离范围更新模型之前触发了Onchange

创建于 2013-10-21  ·  11评论  ·  资料来源: angular/angular.js

在模型更新之前,将触发具有隔离范围的元素的Onchange事件。

例子:

<!doctype html>
<html ng-app="App">
    <head>

        <link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />

        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.js"></script>
        <script src="http://code.angularjs.org/1.0.6/angular.js"></script>
        <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>

        <script type="text/javascript">
            "use strict"

            var App = angular.module('App', []);
            App.controller('Ctrl', function ($scope,$timeout) {

                $scope.change1 = function () {
                    console.warn("inside change", $scope.y);
                }

                $scope.change2 = function () {
                    console.warn("inside change", $scope.x);    
                }

            });

            App.directive("wminput", function () {
                return {
                    restrict: "E",
                    replace: true,
                    scope: {
                        "onChange":"&",
                        "value": "="
                    },
                    template: '<input type="text" data-ng-model="value" data-ng-change="onChange();">'
                }
            });

        </script>

    </head>
    <body>
        <div data-ng-controller="Ctrl">
            "Onchange will be triggered after the model update"
            <input data-ng-change="change1()" data-ng-model="y">
            <br><br>
            "Onchange will be triggered before the model update"
            <wminput on-change="change2()" value="x"></wminput>
        </div>

    </body>
</html>
$compile forms low works as expected confusing bug

最有用的评论

Narretz,我非常不同意。 与开发人员签订的合同中使用了双向绑定优先的代码。 当沿绑定链的任何位置进行更改时,应在更新整个链之前进行更新。 因此,即使另一个指令从该指令继承而来,并且向下绑定到绑定的绑定...如果该模型已更新,则应在同一摘要循环之前更新堆栈底部的原始控制器作用域模型。继续其他功能。 这是消费者的期望。

所有11条评论

有趣的特殊情况... http://plnkr.co/edit/lsrga8qMcbgNWATrVht3?p=preview

仅当onChange函数委托给'&'绑定的父作用域宽度时,才会发生这种情况。

我们一直在研究基于angularjs的RAD工具。
这是一个主要的错误,因为应用程序中的每个小部件都具有isolateScope。
我们通过为onChange创建代理方法解决了该问题。

看看: https :

此致Vinay

您能否发布此代理的示例以及如何使用它? 可能有助于调试。

请参阅以下示例: http :

会尽快修复吗? 这太令人困惑了。

经过进一步考虑,我不得不说这是预期的行为。在plnkr示例中,ngModel的值是控制器和指令范围之间的两个绑定字符串。 现在,当您更改指令中的值时,ngModel将首先更新_isolate_范围,并在同一摘要中触发ngChange。 由于双向绑定尚未选择对指令范围的更改,因此父范围中的ngChange将获得x的“旧”值。 现在,双向绑定观察程序至少需要两个摘要周期才能稳定该值,因此仅在调用ngChange之后才更新控制器范围。
我同意这令人困惑,但这就是它的工作原理。 您可以通过将对象绑定到包含您绑定到ngModel的值的指令来解决此问题。 这样,该值将同时在隔离和控制器范围内通过引用进行设置,并且在执行ngChange时可用: http ://plnkr.co/edit/fs7S6yX1a5aeo1Ese522?p=preview

Narretz,我非常不同意。 与开发人员签订的合同中使用了双向绑定优先的代码。 当沿绑定链的任何位置进行更改时,应在更新整个链之前进行更新。 因此,即使另一个指令从该指令继承而来,并且向下绑定到绑定的绑定...如果该模型已更新,则应在同一摘要循环之前更新堆栈底部的原始控制器作用域模型。继续其他功能。 这是消费者的期望。

有点相关,同样令人困惑。 当使用ngChange来触发共享ngModel另一个字段上的验证时,将在更新$modelValue之前触发更改。 使验证变得复杂。

使用$timeout作为解决方法。 仍然困惑为什么需要这样做。

例子:
http://codepen.io/jakobadam/pen/qmBdrJ?editors=1010

问候,雅各布

有重新计划此问题的计划吗? 也许重新开放?

我遇到了这个问题并仔细阅读了评论,而由于隔离范围,当前的工作方式是有意义的。 当按变更调用触发时期望更新模型并将模型先前迭代一次的结果肯定不是您作为开发人员所期望的行为。

我坚持这个问题,这会被重新审视吗?

我不这么认为。 当前的行为是预期的,尽管在某些情况下不希望这样做,但至少有许多情况是这样。 现在对其进行更改将(a)是一项重大更改,并且(b)使许多用例不受支持(例如,您希望ngChange修改值_before_,它将更新父级)。 在其中一种情况下,您可能无法让所有人都开心,因此我们必须坚持以下版本:

  • 说得通。
  • 不会破坏现有用户。
  • 支持更具体/高级的用例,即使以很少的额外代码为代价(请参阅下文)。

目前执行的ngChange是紧密结合的理念ngModel 。 指令绑定是一个完全独立的概念。 两者可以很好地协同工作,但不应影响彼此的实现/内部工作。

如前所述,如果您的特定回调需要访问更新后的值,则有以下几种选择:

  1. 将更新的值作为参数传递给回调。

  2. 如果您需要异步运行它(即摘要结束并且所有绑定都传播之后),则始终可以在回调中使用$timeout

  3. 如果您需要ngChange的“异步”版本,将其实现为自定义指令也很简单。 (您也可以覆盖内置指令,但我绝对不建议这样做。)例如:

.directive('myAsyncChange', function($timeout) {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, element, attr, ctrl) {
      ctrl.$viewChangeListeners.push(function() {
        $timeout(function() {
          scope.$eval(attr.myAsyncChange);
        });
      });
    }
  };
});
<input ng-model="foo" my-async-change="onChange()" />
此页面是否有帮助?
0 / 5 - 0 等级