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 中找到的信息,我之前的代码应该可以正常工作。如果有人能向我解释为什么我会非常感激:)。
我有一个带有以下代码片段的控制器,
...
$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 中找到的信息,我之前的代码应该可以正常工作。如果有人能向我解释为什么我会非常感激:)。