AngularJS:指令双向数据绑定不起作用

AngularJS : directive two way data binding not working

我有一个带有以下代码片段的控制器,

...
$scope.selected_contents = [];
$scope.$watch('selected_contents', function (sel_contents) {
  console.log(sel_contents, 'selected contents');
}, true);
...

一个指令,

commonDirectives.directive('chkbox', function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    scope : {
        item : '=item',
        selection_pool: '=selectionPool'
    },
    link: function(scope, elem, attrs, ngModel) {
      console.log('selected contents are', scope.selection_pool);
      // watch selection_pool
      scope.$watch('selection_pool', function (pool) {
        console.log(pool, scope.selection_pool, 'pool updated');
        if (_.contains(pool, scope.item)) {
          elem.prop('checked', true);
        }
        else {
          elem.prop('checked', false);
        }
      });
      // toggle the selection of this component
      var toggle_selection = function () {
        if(_.indexOf(scope.selection_pool, scope.item) != -1) {
          scope.selection_pool = _.without(scope.selection_pool , scope.item);
        }
        else {
          scope.selection_pool.push(scope.item);
        }
      };
      elem.on('click', toggle_selection);
    }
  };
});

和一个使用指令的模板,

<tr ng-repeat="content in contents">
      <td><input type="checkbox" selection_pool="selected_contents" item="content" chkbox></td>
</tr>

问题是,指令中 selection_pool 中的更改不会反映到控制器中的 selected_contents 中。我错过了什么?

更新 1:

根据@mohamedrias 的建议,我用 scope.$apply 包装了范围内的更改。这样做只会在添加内容而不是删除内容时更新控制器中的 selected_contents

  ...
  // toggle the selection of this component
  var toggle_selection = function () {
    if(_.indexOf(scope.selection_pool, scope.item) != -1) {
      scope.$apply(function () {
        scope.selection_pool = _.without(scope.selection_pool , scope.item);
      });
    }
    else {
      scope.$apply(function () {
        scope.selection_pool.push(scope.item);
      });
    }
  };
  ...

Angular uses name-with-dashes for attribute names and camelCase for the corresponding directive name

来自 here.

变量应该从这个selection_pool:

<input type="checkbox" selection_pool="selected_contents" item="content" chkbox>

selection-pool:

<input type="checkbox" selection-pool="selected_contents" item="content" chkbox>

并将此 selectionPool 放入指令中:

scope : {
    item : '=item',
    selectionPool: '=selectionPool'
}

编辑:因为selectionPool是一个数组,你应该使用$watchCollection:

scope.$watchCollection('selectionPool', function (pool) 

并且当您 toggle_selection 函数中的数组中的 add/remove 值时,应该包含在 $timeout 函数中:

$timeout(function () {
            if (_.indexOf(scope.selectionPool, scope.item) != -1) {
                scope.selectionPool = _.without(scope.selectionPool, scope.item);
             } else {
                 scope.selectionPool.push(scope.item);
             }
});

这是为了确保之后会应用 digest 循环。

这是在 jsfiddle 上运行的代码:http://jsfiddle.net/0rvcguz0/3/

经过一整天的研究,我最终 here。如果有人在使用 Angularjs 范围时遇到任何问题,我强烈建议您阅读它。

在我的案例中,正确的解决方案是用一个对象包裹 selected_contents。例如

$scope.selected = {};
$scope.selected.contents = [];

然后在模板中将 selcted_contents 替换为 selected.contents

但我仍然不明白的是,[] 或 Array 也是一个对象。根据我在 wiki 中找到的信息,我之前的代码应该可以正常工作。如果有人能向我解释为什么我会非常感激:)。