【问题标题】:Behaviour bindToController in child scope versus isolated scope子范围与隔离范围中的行为 bindToController
【发布时间】:2015-10-06 14:19:17
【问题描述】:

我在玩 bindToController 指令选项。我偶然发现了使用子作用域与隔离作用域的行为之间看似奇怪的区别。当我使用隔离作用域时,会为指令创建一个新作用域,但对绑定控制器属性的更改会转发到父作用域。然而,当我改用子范围时,我的例子就中断了。 (根据http://blog.thoughtram.io/angularjs/2015/01/02/exploring-angular-1.3-bindToController.html#improvements-in-14 应该允许使用bindToController 使用子作用域)

代码:

{
    restrict: 'E',
    scope: {},
    controller: 'FooDirCtrl',
    controllerAs: 'vm',
    bindToController: {
        name: '='
    },
    template: '<div><input ng-model="vm.name"></div>'
};

工作演示https://jsfiddle.net/tthtznn2/

使用子作用域的版本:

{
    restrict: 'E',
    scope: true,
    controller: 'FooDirCtrl',
    controllerAs: 'vm',
    bindToController: {
        name: '='
    },
    template: '<div><input ng-model="vm.name"></div>'
};

演示:http://jsfiddle.net/ydLd1e00/

对名称的更改将转发到子范围,但不会转发到父范围。这与绑定到隔离范围相反。这是为什么呢?

【问题讨论】:

  • 因为 vm.name 是字符串和 javascript 值传递?可能是,再创建一个嵌套对象,如 vm.data.name 并绑定数据。
  • 在后一种情况下绑定到对象确实有效(参见:jsfiddle.net/sbvm1nd4)。我仍然不明白为什么隔离范围和子范围之间存在不同,但我希望隔离范围会遇到同样的问题。
  • 其原型继承的 javascript 性质 - github.com/angular/angular.js/wiki/Understanding-Scopes,我个人认为 angular 可以将这种行为更改为一致,因为所有表达式都是通过 angular 的 AST 解析的,但可能是他们选择遵循 javascript 的性质。
  • 我了解 JavaScript 的原型继承。我的问题是,通过定义与控制器的双向绑定,我希望将更改传播到父范围(您同意这是 bindToController 选项的用途,对吧?)。
  • 我知道范围。我也知道关于范围和角度的讨论。他们现在都不是我真正感兴趣的。我要问的是:因为子范围和隔离范围都创建了一个新范围。 (是的,第一个是通过原型继承创建的,我完全同意这一点)。但是为什么第一个选项双重绑定到新创建的范围,而第二个选项双重绑定到旧/父范围?对我来说,这似乎不一致。

标签: angularjs angularjs-directive angularjs-scope


【解决方案1】:

这是因为您为两个控制器使用了相同的别名(与 cmets 中提到的对象与字符串值无关)。

您可能知道,controller as alias 语法只是在作用域上创建一个alias 属性并将其设置为控制器实例。由于您在两种情况下都使用vm 作为别名(MainCtrlFooDirCtrl),所以在 normal 子范围的情况下,您正在“隐藏”MainCtrl 别名。 (在这种情况下,“正常”意味着“原型继承自父范围”。) 因此,当您尝试在新范围上评估 vm.namevmMainCtrl)以获得“父值”时,它实际上是在评估 FooDirCtrl.name(未定义),当您正在尝试分配回父范围。

isolate 范围版本不受影响,因为该范围没有从其父范围继承。

Updated fiddle


更新: 仔细查看源代码,这可能是一个错误(因为“追溯”添加了对非隔离范围的bindToController 的支持)。 由于原型继承,我们似乎已经摆脱了这个错误,但是当名称发生冲突时,我们就不走运了。

我必须仔细看看它是否确实是一个错误以及它是否“可修复”,但现在你可以通过为你的控制器使用不同的别名来解决它(参见上面的小提琴)。


这(部分)是为什么我不喜欢使用 vm 作为我的控制器别名(尽管流行的风格指南建议使用它):)

让我们在angular.js#13021 中跟踪它。

【讨论】:

  • 感谢您的回复。我会密切关注线程的。当我们对这个问题更进一步时,我会接受答案。顺便说一句,我也不喜欢vm 这个名字,tbh,我偷了小提琴,只为第二个例子调整了它;-)
  • @Jan-WillemGmeligMeyling:顺便说一句,我已经提交了修复:angular.js#13025
  • 它已经合并了。因此,这将在 v1.5.0-beta.2 之后正常工作。
  • 它也合并到了4天前发布的1.4.8中。
  • 看起来这个错误已经被重新引入。我正在使用 1.5.8 并注意到同样的问题
猜你喜欢
  • 1970-01-01
  • 2016-04-30
  • 1970-01-01
  • 2014-06-23
  • 1970-01-01
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多