Javascript 双向绑定在具有转移范围的指令中不起作用

Javascript 双向绑定在具有转移范围的指令中不起作用,javascript,angularjs,Javascript,Angularjs,我在控制器中有一个文本框,它绑定到modelname。控制器内有一个指令,指令内有另一个文本框,该文本框绑定到同一型号name: <div class="border" ng-controller="editCtrl"> Controller: editCtrl <br/> <input type="text" ng-model="name" /> <br/> <tabs> Directive: ta

我在控制器中有一个文本框,它绑定到model
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>

控制器:editCtrl

指令:制表符

mod.指令('tabs',函数(){
返回{
限制:'E',
是的,
模板:
'',
};
});
当您在外部文本框中键入内容时,它将反映在内部文本框中,但如果您在内部文本框中键入内容,它将停止工作,即两个文本框不再反映相同的值

见以下示例:

我也尝试过使用双向绑定attr(
scope:{name:'='}
),但它给出了语法错误。使用
scope:{name:'@'}
也有同样的效果

任何帮助都将不胜感激


除了公认的答案之外,还真的帮助我理解了儿童SCPOE中的原型遗传。我强烈建议对作用域有问题的人仔细阅读。

语法错误意味着您写错了什么。它与特定的框架/库无关。您可能忘记添加“,”或关闭一个妄想。再次查看

我认为问题与范围界定有关。最初,内部文本框没有设置
名称
,因此它是从外部范围继承的。这就是为什么在外框中键入内容会反映在内框中。但是,一旦在内部框中输入,内部范围现在包含
名称
,这意味着它不再绑定到外部
名称
,因此外部文本框不会同步

适当的修复方法是只在作用域中存储模型,而不是存储您的值。我在创建模型对象(
数据
)并引用其上的值的技巧中修复了它

不正确的代码修改指令中的范围,正确的代码修改指令中范围中的模型。这种细微的差异允许范围继承正常工作

我相信Miško Hevery的措辞是,作用域应该只写在控制器中,而只读在指令中


更新:reference:

带有
transclude:true
的指令将导致该指令创建一个新的(被转移的)子作用域。此新范围原型通常从父范围继承。在您的情况下,父作用域是与editCtrl控制器关联的作用域

在子作用域(即ng模型)中使用双向数据绑定来绑定到包含基元值的父作用域属性(例如,
name
)总是会导致问题——我应该说,它没有按预期工作。当在子对象中更改范围属性时(例如,在第二个文本框中键入),子对象将创建一个新的范围属性,该属性将隐藏/隐藏同名的父范围属性。如果父属性包含基元值,则在创建子属性时,该值(基本上)复制到子属性。子范围(例如,第二个文本框)中的未来更改仅影响子属性

在输入第二个文本框之前(即,在子对象中更改属性之前),子对象/转置范围通过原型继承在父对象范围中查找
name
属性(下图中的虚线)。这就是两个文本框最初保持同步的原因。下面,如果在第一个文本框中键入“Mark”,则作用域是这样的:

我创建了一个可以检查这两个作用域的。在输入第二个文本框之前,单击第二个文本框旁边的“显示范围”链接。这将允许您查看转移的子范围。您会注意到,此时它没有
名称
属性。清除控制台,在第二个文本框中键入,然后再次单击链接。您将注意到,子范围现在有一个
名称
属性,初始值是父属性的值(“标记”)。如果在第二个文本框中键入“likes Angular”,则作用域如下所示:

有两种解决方案:

  • 按照@pgreen2的建议去做(这是“最佳实践”解决方案)——使用对象而不是原语。使用对象时,子/转移范围不会获得新属性。这里只有原型遗传在起作用。在下图中,假设editCtrl的$scope定义了以下对象:
    $scope.myObject={name:“Mark”,另一个属性:…}

  • 在子作用域中使用$parent(这是一个脆弱的解决方案,不推荐使用,因为它会对HTML结构进行假设):在元素中的内部使用
    ng model=“$parent.name”
    。上面的第一张图片显示了它是如何工作的
  • 使用
    作用域:{name:'='}
    时发生语法错误,因为在使用双向数据绑定(即使用'=')时,不允许插值,即不能使用{}}。使用
    代替

    使用“@”的工作原理与transclude的工作原理相同,因为ng transclude使用的是transclude作用域,而不是使用
    scope:{…}
    创建的隔离作用域


    有关示波器(包括图片)的更多信息,请参见

    我最近看了一段视频,其中Miško Hevery谈到了同样的问题(我就是这样认识到的)。如果我能找到,我会更新答案。谢谢!这似乎解决了我的问题:)哇。。文件应反映这一点。非常棘手的问题。是的,我知道语法错误的意思,但我没有看到任何语法错误。在这里查看:@Uzair,我添加了一些图片。(这将有助于未来的读者,他们最终也会来到这里。)使用ng transclude与指定任何子项相比有什么优势
    mod.directive('tabs', function() {
      return {
        restrict: 'E',
        transclude: true, 
        template:
          '<div class="border" ng-transclude></div>',
      };
    });