【问题标题】:AngularJS 1.4 directives: scope, two way binding and bindToControllerAngularJS 1.4 指令:范围、双向绑定和 bindToController
【发布时间】:2015-10-29 22:58:21
【问题描述】:

更新:在代码的另一部分一定是愚蠢的。它现在可以工作了,所以 bindToController 语法很好。

我们使用的是 AngularJS 1.4,它在指令中引入了 new way to use bindToController

经过大量阅读(可能还没有完全理解所有内容),我们这样定义指令:

  .directive('mdAddress', function mdAddress() {
    var directive = {
      restrict: 'EA',
      scope: {},
      bindToController: {
        address: '='
      },
      templateUrl: 'modules/address/address.html',
      controller: AddressController,
      controllerAs: 'dir'
    };

像这样从另一个视图调用它:

  <md-address address="vm.address"></md-address>

已经在视图控制器中定义了:

  vm.address = {
    street: null,
    countryCode: null,
    cityCode: null,
    postalCode: null
  };

像这样引用指令模板中的变量:

  <md-input-container>
    <label>{{'ADDRESSNUMBER' | translate}}</label>
    <input type="number" ng-model="dir.address.streetNumber">
  </md-input-container>

我们花了 4 小时试图弄清楚为什么我们的指令不起作用。好吧,它可以工作,但是控制器和指令之间的双向绑定没有,vm.address.street 被无可救药地设置为 null。

一段时间后,我们只是尝试了旧方法:

  .directive('mdAddress', function mdAddress() {
    var directive = {
      restrict: 'EA',
      scope: {
        address: '='
      },
      bindToController: true,
      templateUrl: 'modules/address/address.html',
      controller: AddressController,
      controllerAs: 'dir'
    };

它神奇地起作用了。知道为什么

【问题讨论】:

  • 您的modules/address/address.html 模板中有什么?如果您试图在模板中完全引用vm,那么这将导致空问题,因为vm 在您的指令范围内不存在。此外,如果您试图仅绑定到指令模板中的address,那么当您将控制器绑定为dir 时,它也不存在,所以它必须是dir.address
  • 在模板中我们引用了dir的元素:&lt;input type="number" ng-model="dir.address.streetNumber"&gt;。我编辑了主要帖子以澄清这一点。谢谢。
  • 请为这两种情况提供两个 plunker。对此有简单的解释,但纯文本并不能清楚地说明您到底做了什么。
  • 我在升级到 1.4+ 之前遇到了类似的问题。任何可能的原始问题仍然引用旧版本的 Angular?
  • 嗯,这是可能的,尽管我很确定我们在尝试之前更改了角度版本。现在很难说:)

标签: javascript angularjs angularjs-directive angularjs-scope


【解决方案1】:

更新:

感谢reference to this blog post,我需要更新我的答案。从 AngularJS 1.4 开始,你可以使用

scope: {},
bindToController: {
  variable: '='
}

这将与旧语法(完全)做同样的事情:

scope: {
  variable: '='
},
bindToController: true

AngularJS 源代码中解释这种行为的有用行:

if (isObject(directive.scope)) {
  if (directive.bindToController === true) {
    bindings.bindToController = parseIsolateBindings(directive.scope,
                                                     directiveName, true);
    bindings.isolateScope = {};
  } else {
    bindings.isolateScope = parseIsolateBindings(directive.scope,
                                                 directiveName, false);
  }
}
if (isObject(directive.bindToController)) {
  bindings.bindToController =
      parseIsolateBindings(directive.bindToController, directiveName, true);
}

来源:AngularJS 1.4.0

原答案:

希望我可以向您解释为什么您遇到的这种行为是正确的,以及您在哪里误解了范围绑定的概念。

让我解释一下,你在第一个代码 sn-p 中做了什么:

.directive('mdAddress', function mdAddress() {
    var directive = {
      restrict: 'EA',
      scope: {},
      bindToController: {
        address: '='
      },
      templateUrl: 'modules/address/address.html',
      controller: AddressController,
      controllerAs: 'dir'
    };

使用scope: {},您为mdAddress 指令创建了一个隔离范围(没有任何继承)。这意味着:父控制器和您的指令之间没有数据传递。

考虑到这一点,关于您的第二个代码 sn-p:

<md-address address="vm.address"></md-address>

您的父控制器/视图中的vm.address 将作为表达式分配给指令的地址属性,但是由于您之前定义了一个隔离范围,数据不会传递到AddressController,因此在@ 中不可用987654332@值。

让我们将scope 对象定义视为“将传入哪些数据”,将bindToController 视为“哪些数据将在我的视图的controllerAs 对象中可用”。

那么,现在让我们看看最后一个(和工作代码 sn-p):

.directive('mdAddress', function mdAddress() {
    var directive = {
      restrict: 'EA',
      scope: {
        address: '='
      },
      bindToController: true,
      templateUrl: 'modules/address/address.html',
      controller: AddressController,
      controllerAs: 'dir'
    };

您还创建了一个隔离作用域,但这次您添加了address 属性以作为表达式传入。所以现在你从第二个 sn-p 的视图中传入的address 将在控制器的范围内可用。现在设置bindToController: true,会将所有当前范围的属性绑定到控制器(或者更可能是controllerAs 对象)。现在,它可以正常工作了,因为数据将被传递到作用域,而数据将被传递到控制器的模板作用域。

这个简短的概述是否有助于您更好地理解 scopebindToController 定义对象的概念?

【讨论】:

  • 非常感谢您的回答!这是有道理的,我完全理解你解释的第二部分,但第一部分似乎与我链接的文章完全相反(关于新的 bindToController 功能)。特别是当它说“这意味着我们可以将我们的范围:{名称:'='}示例绑定移到它上面,以更明确地表明隔离绑定实际上是继承并绑定到控制器的”,并将scope: {name: '='}, bindToController: true替换为scope: {}, bindToController: {name: '='}.
  • 确实,感谢您的回复。你是对的,我需要恢复我的部分答案。重要的一行是文章中提到的 AngularJS 源代码中的那一行 - 所以这两种情况下的行为应该是相同的。所以也许你的代码中真的有一些奇怪的错误/错字?或者您可以从您的问题中重现所有内容吗?非常有趣的话题!
  • 谢谢,我想我可能误解了这篇文章:)。无论如何,查看 AngularJS 代码,会不会是 scope: {} 返回 isObject 为真,因为它是一个空对象,而不是 null?然后它将进入ifsentence 的第一部分...我检查了isObject 的AngularJS 源代码,但我不确定...
  • 是的,你是对的,在这种情况下,第一个 if 条件将被评估为 true(因为 {} 确实是一个对象)。在这个 if 中,将触发 else 分支。但是第二个外部 if 条件也将被评估为 true,因为 directive.bindToController 也是您的第一个代码 sn-p 中的一个对象。所以bindings.bindToControllerbindings.isolateScope 将被填充。还不知道这是否会遇到您遇到的这些问题。知道您是否仍然可以重现该问题真的很有趣?!
  • "这个简短的概述是否帮助您更好地理解范围和 bindToController 定义对象的概念?"确实为我做了!
猜你喜欢
  • 2016-04-30
  • 1970-01-01
  • 1970-01-01
  • 2014-04-28
  • 1970-01-01
  • 1970-01-01
  • 2015-08-15
  • 1970-01-01
相关资源
最近更新 更多