AngularJS - 带 ng-transclude 的指令,无双向绑定

AngularJS - directive with ng-transclude, no two-way binding

看到DEMO

<body ng-controller="MainCtrl">

    {{ obj }}

    <dir>
      <input type="text" ng-model="obj" />
    </dir>

  </body>

为什么当我使用 ng-transclude 更改自定义指令中的 obj 范围变量时,我没有在 MainCtrl $scope.obj.[=21= 中更改它]

但是当我在 MainCtrl 中有 $scope.obj = { name : 'test' }; 时,双向绑定按我预期的方式工作。

查看工作DEMO

<body ng-controller="MainCtrl">

    {{ obj.name }}

    <dir>
      <input type="text" ng-model="obj.name" />
    </dir>

  </body>

这种行为的解释是什么?

从子作用域访问父作用域上的原始变量时出现问题。您有一个子作用域,因为 transclude: true 创建了一个新作用域。

您真的应该阅读 this article 以深入了解正在发生的事情。

文章要点:

Scope inheritance is normally straightforward, and you often don't even need to know it is happening... until you try 2-way data binding (i.e., form elements, ng-model) to a primitive (e.g., number, string, boolean) defined on the parent scope from inside the child scope.

This issue with primitives can be easily avoided by following the "best practice" of always have a '.' in your ng-models.

发生的事情是在涉及基元时没有咨询父范围。这是 Javascript 的事情,甚至 Angular 的都不是。

我还创建了一个 Demo 隐藏在子作用域中的对象。 (阴影非原始对象):

app.directive('dir', function () {
    return {
        restrict: 'E',

        scope: true,
        template: "<div><input type=\"text\" ng-model=\"obj.name\" /></div>",
        link: function(scope, element, attrs) {
          scope.obj = {name : "newname"}; 
        }

    };
});

被嵌入的 html 生成一个 MainCtrl 的子作用域,当写入这个新的 属性 (obj) 时,子作用域生成一个覆盖父作用域的新作用域.

The prototype chain is not consulted, and a new aString property is added to the childScope. This new property hides/shadows the parentScope property with the same name.

修改后的版本有效,因为子作用域(嵌入)首先访问 obj(引用),然后访问 属性 名称

https://github.com/angular/angular.js/wiki/Understanding-Scopes

了解有关作用域继承的更多信息

以及 http://angular-tips.com/blog/2014/03/transclusion-and-scopes/

处的包含和作用域行为

当您从同一范围查询 obj 的值时,这有效 - 指令的范围:

<body ng-controller="MainCtrl">

  {{ obj }}

  <dir>
    <p>
      The following text will be synched with the model:
    </p>
    <span>{{ obj }}</span>
    <br/>
    <input type="text" ng-model='obj' />
  </dir>

</body>