双向绑定不在指令中与transcluded范围一起工作

Uza*_*ooq 58 javascript angularjs

我在控制器中有一个绑定模型的文本框name.控制器内部有一个指令,指令中有另一个文本框绑定到同一个模型name:

<div class="border" ng-controller="editCtrl">
   Controller: editCtrl <br/>
   <input type="text" ng-model="name" />
   <br/>
   <tabs>
      Directive: tabs <br/>
      <input type="text" ng-model="name"/>
   </tabs>
</div>
Run Code Online (Sandbox Code Playgroud)

mod.directive('tabs', function() {
  return {
    restrict: 'E',
    transclude: true, 
    template:
      '<div class="border" ng-transclude></div>',
  };
});
Run Code Online (Sandbox Code Playgroud)

当您在外部文本框中键入内容时,它会反映在内部文本框中,但如果您在内部文本框中键入内容,它将停止工作,即两个文本框不再反映相同的值.

请参阅示例:http://jsfiddle.net/uzairfarooq/MNBLd/

我也试过使用双向绑定attr(scope: {name: '='})但它给出了语法错误scope: {name: '@'}.并且使用具有相同的效果.

任何帮助将不胜感激.

除了接受的答案,这篇文章确实帮助我理解了儿童scpoes的原型继承.我强烈建议任何有范围问题的人彻底阅读.

Mar*_*cok 128

指令中的transclude: true结果指令创建一个新的(已转换的)子范围.这个新范围原型继承自父范围.在您的情况下,父作用域是与editCtrl控制器关联的作用域.

在子范围(即ng-model)中使用双向数据绑定绑定到包含原始值(例如name)的父范围属性总是会导致问题 - 我应该说它不能按预期工作.当在子项中更改scope属性时(例如,您键入第二个文本框),子项创建一个新的scope属性,该属性隐藏/隐藏同名的父scope属性.如果父属性包含原始值,则在创建子属性(实质上)将该值复制到子属性.子范围的未来更改(例如,第二个文本框)仅影响子属性.

在键入第二个文本框之前(即,在子项中更改属性之前),子/ transcluded name范围通过原型继承(下图中的虚线)在父作用域中查找属性.这就是为什么两个文本框最初保持同步.下面,如果在第一个文本框中键入"Mark",则这是范围的样子:

transcluded范围遵循继承链

我创建了一个小提琴,您可以在其中检查两个范围.在键入第二个文本框之前,单击第二个文本框旁边的"显示范围"链接.这将允许您查看已转移的子范围.您会注意到此时它没有name属性.清除控制台,键入第二个文本框,然后再次单击该链接.您会注意到子范围现在具有name属性,初始值是父属性具有的值("标记").如果您在第二个文本框中键入"喜欢Angular",这就是范围的样子:

transcluded原始隐藏父属性

有两种解决方案:

  1. 做什么@pgreen2建议(这是"最佳实践"解决方案) - 使用对象而不是原语.使用对象时,子/ transcluded范围不会获得新属性.这里只有原型继承.假设editCtrl的$ scope定义了这个对象
    $scope.myObject = { name: "Mark", anotherProp: ... }:
    父母的对象
  2. 在子范围中使用$ parent(这是一个脆弱的解决方案,不推荐,因为它对HTML结构做出了假设):ng-model="$parent.name"在<tabs>元素内的<input>内使用.上面的第一张图片展示了它的工作原理.

使用scope: {name: '='}时会出现语法错误,因为在使用双向数据绑定时(即使用'='时),不允许插值 - 即,{{}}不能使用.而不是<tabs name="{{name}}">使用<tabs name="name">.

使用'@'与transclude情况相同,因为ng-transclude使用transcluded范围,而不是使用创建的隔离范围scope: { ... }.

对于(批量)有关范围(包括图片)的更多信息,请参阅
AngularJS中范围原型/原型继承的细微差别是什么?

  • @Uzair,我添加了一些照片.(这有望帮助未来的读者.) (4认同)

pgr*_*en2 10

我认为问题与范围有关.最初内部文本框没有nameset,因此它继承自外部作用域.这就是为什么在外框中输入反映在内框中的原因.但是,一旦在内部框中键入内部,内部作用域现在包含name这意味着它不再绑定到外部,name因此外部文本框不会同步.

适当的修复方法是仅在范围内存储模型,而不是您的值.我在http://jsfiddle.net/pdgreen/5RVza/修复了它 .诀窍是创建一个模型对象(data)并在其上引用值.

错误的代码修改了指令中的范围,正确的代码修改了指令范围内的模型.这种微妙的差异允许范围继承正常工作.

我相信MiškoHevery所说的方式是,范围应该在控制器中是只写的,而在指令中是只读的.

更新:参考:https://www.youtube.com/watch?v = ZhfUv0spHCY#t = 29m19s

  • 哇..文档应该反映这一点.非常棘手的问题. (3认同)