【问题标题】:AngularJS : directive two way data binding not workingAngularJS:指令两种方式数据绑定不起作用
【发布时间】:2015-09-29 20:29:46
【问题描述】:

我有一个控制器,代码如下 sn-p,

...
$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);
      });
    }
  };
  ...

【问题讨论】:

  • 您必须在指令的点击处理程序中使用scope.$apply()
  • @mohamedrias 你能解释一下吗?我想知道为什么需要它。

标签: angularjs angularjs-directive angularjs-scope angularjs-ng-repeat


【解决方案1】:

Angular 使用带破折号的 name-with-dashes 来表示属性名,使用 camelCase 表示 对应的指令名称

来自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 函数中从数组中添加/删除值时,应将其包裹在$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/

【讨论】:

  • sorry 还是同样的问题,移除内容依然没有反映在控制器的selected_contents
  • 对不起,我理解的有些不同,现在我想我已经回答了这个问题
  • $scope.$watchCollection 为我做了。我正在使用 $scope.$watch 测试该行为,但它没有反映对象上的更改
【解决方案2】:

研究了一整天后,我最终找到了here。如果有人对Angularjs 范围有任何疑问,我强烈建议您阅读它。

在我的情况下,正确的解决方案是用一个对象包装selected_contents。例如

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-22
    • 1970-01-01
    • 2012-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-23
    相关资源
    最近更新 更多