简要介绍我的问题
我有一个动态显示复选框列表的指令。它有一个名为options
的参数,该参数应该是如下所示的数组,以便正确显示复选框列表。例如:
var options = [
{
id: 1,
label: 'option #1'
},
{
id: 2,
label: 'option #2'
},
{
id: 3,
label: 'option #3'
}
];
因此,通过将此数组传递给我的指令,将显示一组三个复选框。
此外,该指令需要具有选中/取消选中复选框结果的ngModel
(此对象始终以初始化方式传递)。例如:
var result = {
"1": true,
"2": true,
"3": false
};
这种情况意味着选中第一个和第二个复选框(带有id=1
和id=2
的选项),而第三个复选框(带有id=3
的选项)被取消选中。
我的指令
模板.html
<div ng-repeat="option in options track by $index">
<div class="checkbox">
<label>
<input type="checkbox"
ng-model="result[option.id]">
{{ ::option.label }}
</label>
</div>
</div>
指令.js
angular
.module('myApp')
.directive('myDirective', myDirective);
function myDirective() {
var directive = {
templateUrl: 'template.html',
restrict: 'E',
require: 'ngModel',
scope: {
options: '='
},
link: linkFunc
};
return directive;
function linkFunc(scope, element, attrs, ngModel) {
scope.result;
ngModel.$render = setResult;
function setResult() {
scope.result = ngModel.$viewValue;
};
};
};
我想要实现的目标
无论我在哪里使用我的指令,我都希望能够在ngModel
发生变化时触发一个函数。当然,我想使用ngChange
.到目前为止,我有以下内容:
<my-directive
name="myName"
options="ctrlVM.options"
ng-model="ctrlVM.result"
ng-change="ctrlVM.selectionChanged()">
</my-directive>
但每当模型更改时,都不会触发.selectionChanged()
函数。任何人都知道为什么这不起作用,因为我希望它有效?
首先,请尝试提供jsfiddle,codepen等代码片段链接,以便其他人轻松回答您的问题。
您在这种情况下的问题是,在传递对象的引用时,您永远不会更新ctrlVM.result
对象,并且即使您通过调用ngModel.$setViewValue()
手动更新模型,该引用也永远不会更改。
要解决此问题,只需通过手动调用ngModel.$setViewValue()
来更新模型并传入新对象,以便引用更改并触发ngChange
指令逻辑。
我已经添加了执行此操作的逻辑,它将成功触发更改。查看下面的代码:
angular
.module('myApp', [])
.directive('myDirective', myDirective)
.controller('MyController', function($timeout) {
var vm = this;
vm.options = [{
id: 1,
label: 'option #1'
}, {
id: 2,
label: 'option #2'
}, {
id: 3,
label: 'option #3'
}];
vm.result = {
"1": true,
"2": true,
"3": false
};
vm.selectionChanged = function() {
vm.isChanged = true;
$timeout(function() {
vm.isChanged = false;
}, 500)
}
});
function myDirective() {
var directive = {
templateUrl: 'template.html',
restrict: 'E',
require: 'ngModel',
scope: {
options: '='
},
link: linkFunc
};
return directive;
function linkFunc(scope, element, attrs, ngModel) {
scope.result;
ngModel.$render = setResult;
function setResult() {
scope.result = ngModel.$viewValue;
};
scope.updateValue = function(val) {
ngModel.$setViewValue(Object.assign({}, val))
}
};
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
<div ng-app="myApp">
<script type="text/ng-template" id="template.html">
<div ng-repeat="option in options track by $index">
<div class="checkbox">
<label>
<input type="checkbox"
ng-model="result[option.id]" ng-click="updateValue(result)">
{{ ::option.label }}
</label>
</div>
</div>
</script>
<div ng-controller="MyController as ctrlVM">
<my-directive name="myName" options="ctrlVM.options" ng-model="ctrlVM.result" ng-change="ctrlVM.selectionChanged()">
</my-directive>
<div> Data: {{ctrlVM.result}} </div>
<div> isChanged: {{ctrlVM.isChanged}} </div>
</div>
</div>
@Gaurav
正确地识别了问题(ng-change
永远不会被调用,因为对象引用不会改变)。 下面是一个更简单的解决方案,不需要手动克隆到控制器的模型中:
-
为
ng-change
属性添加绑定:scope: { options: '=', ngChange: '&' // Add this, creates binding to `ctrlVM.selectionChanged()` }
-
将
ng-change
添加到复选框模板:<input type="checkbox" ng-model="result[option.id]" ng-change="ngChange()">
现在,当任何复选框更改时,它将自动调用外部ng-change
函数,而无需克隆到模型中的中间步骤。