更改控制器初始化中的范围不适用于指令

时间:2015-07-29 22:57:05

标签: javascript angularjs angularjs-directive

我有这个指令:

angular.module("app", [])
  .directive("myDirective", myDirective);

function myDirective() {
  return {
    template: '{{vm.numbers}}',
    scope: {
      numbers: '='
    },
    controller: MyController,
    controllerAs: 'vm',
    bindToController: true,
  };
}

function MyController($timeout) {
  var vm = this;
  vm.numbers.push(3);
  $timeout(function() {
     vm.numbers.push(4);
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>

<div ng-app="app">
  <my-directive numbers="[1,2]"></my-directive>
</div>

为什么3没有被推到阵列?

2 个答案:

答案 0 :(得分:3)

=@之间存在明显的语法差异。双向=绑定的一个特性是,当属性值不是作用域属性名称时,应该小心处理,因为它不适用于此。

在您的示例中发生的事情是'[1,2]'字符串被解析为数组,并且在控制器函数运行时可用作vm.number范围属性。使用vm.numbers.push(3)所做的更改已应用于匿名数组的副本,并且未在任何位置观察到这些更改。控制器功能完成后,第一个摘要周期启动,vm.number再次被[1, 2]数组覆盖。之后$timeout函数启动并使用vm.numbers.push(4)进行另一项更改。 vm.number的变化仅在此时才被观察到。

当匿名数组或对象被馈送到双向指令绑定时会发生这种情况。将vm.number分配给其他人也会遇到问题。

由于@绑定仅适用于文本,因此它也不是一个选项。你可以这样做

function myDirective() {
  return {
    template: '{{vm.numbers}}',
    scope: {},
    controller: MyController,
    controllerAs: 'vm',
    bindToController: true,
  };
}

function MyController($timeout, $parse, $attrs) {
  var vm = this;
  vm.numbers = $parse($attrs.numbers)() || [];
  vm.numbers.push(3);
  $timeout(function() {
     vm.numbers.push(4);
  });
}

答案 1 :(得分:1)

当控制器执行时,vm.numbers会根据您的逻辑进行更新。然后链接阶段启动并且范围变量从您的标记和范围中的名称设置,但您将失去控制器的临时更改。

我添加了一些显示此序列的控制台日志:

in controller=> [1, 2, 3]
in link, scope=> [1, 2, 3] attrs=> [1,2]
in timeout method=> [1, 2]

一种方法是@estus建议的,自己连接参数。另一种方法可能是重写逻辑,以便您可以依靠angular来管理传递的。