具有隔离范围的角度双向绑定似乎是单向的

时间:2014-12-19 01:32:21

标签: javascript angularjs

我使用隔离范围编写了一个简单的点击编辑指令,以便它可以重复使用。当我使用它时,控制器范围中的源值(' =')永远不会更新,尽管它的原始值在指令中应用。它好像绑定是单向的(' @')。

以下是代码:

app.directive("ngClickToEdit", function() {
    return {
        template:
            '<div>' +
                '<div ng-show="enabled">' +
                    '<input ng-change="validator()" ng-blur="enabled=false"  ng-model="source"/>' +
                '</div>' +
                    '<div ng-show="!enabled" ng-bind="source" ng-click="enable()"></div>' +
            '</div>',
        restrict: "E",
        replace: true,
        scope: {
            validator: '&',
            source: '=',
        },
        link: function(scope, element) {
            scope.enabled = false;

            var input = element.children()[0].firstChild;

            scope.enable = function() {
                scope.enabled = true;
                setTimeout(function() {
                    input.focus();
                    input.select();
                }, 200);
            };
        },
    };
});

这是控制器中的一个调用(编辑为包装在ng-if div块中):

<div ng-if='name'>
    <ng-click-to-edit validator='validateName()' source='name' />
</div>

当调用控制器范围中的validateName()时,将调用&#39; name&#39;的值。是指令输入控件中的原始值而不是(已更改)值。该模型未更新。为什么呢?

解决: ng-if块创建子范围,由于prototypal inheritance而将name作为字符串原语传递。将对象引用传递给指令可以解决问题。请在此处查看revised plunker

1 个答案:

答案 0 :(得分:0)

这是因为外部范围name尚未分配内部范围source。当您使用"="声明隔离范围时,Angular $watch会在两个值中进行更改(请参阅code),并执行双向绑定,但$ watch避难所&t在调用validator时被解雇。

您可以使用以下代码进行检查:

$scope.validateName = function(){
  console.log("outside directive: name = " + $scope.name);

  $timeout(function(){
    console.log("but just after digest cycle: name = " + $scope.name);
  });
};

你可以做一些事情:

1)您可以在$timeout之后触发验证器:

scope.localValidate = function(){
   $timeout(function(){ scope.validator(); });
};

和模板:

<input ng-change="localValidate()"..>

2)你可以在$ source中关注更改,然后点击$validator(而不是ng-change):

scope.$watch("source", function(){
    scope.validator();
});

3)您可以将值传递给验证器函数:

<input ng-change="validator({name: source})"..>