Angularjs:ng-repeat中的复杂指令,如何绑定ngModel或ngChecked指令并使其工作?给定数组:
+----+-----------+----------+----------+-------+
| id | name | parentid | haschild | value |
+----+-----------+----------+----------+-------+
| 1 | parent | null | false | true |
| 2 | id1 child | 1 | true | true |
| 3 | id2 child | 2 | true | true |
| 4 | id3 child | 3 | false | true |
| 5 | id1 child | 1 | true | true |
| 6 | id5 child | 5 | false | true |
+----+-----------+----------+----------+-------+
$scope.permission = [
{"id":1,"name":"parent","value":true,"parentid":"","haschild":false},
{"id":2,"name":"id-1 child","value":true,"parentid":1,"haschild":true},
{"id":3,"name":"id-2 child","value":true,"parentid":2,"haschild":true},
{"id":4,"name":"id-3 child","value":true,"parentid":3,"haschild":false},
{"id":5,"name":"id-1 child","value":true,"parentid":1,"haschild":true},
{"id":6,"name":"id-5 child","value":true,"parentid":5,"haschild":false}
];
所以在 HTML 中
<div ng-repeat="x in permission" ng-if="x.parentid == undefined" has-child="{{x}}"></div>
和指令
myApp.directive('hasChild', function($compile) {
return function(scope, element, attrs) {
var j = JSON.parse(attrs.hasChild);
function generatePermissionDom(thisElement,thisParent)
{
angular.forEach(scope.permission,function(o,i){
if(thisParent.id==o.parentid)
{
var e = $('<div><input type="checkbox" ng-model="o.value"/>'+o.name+'</div>');
generatePermissionDom(e,o);
$(thisElement).append(e);
}
});
}
if(j.haschild)
angular.forEach(scope.permission,function(o,i){
if(o.parentid==j.id)
{
var e = $('<div><input type="checkbox" ng-model="o.value"/>'+o.name+'</div>');
if(o.haschild)
generatePermissionDom(e,o);
$(element).append(e);
}
});
var p = $(element);
$compile(element.contents())(scope);
}
});
那么如何在指令中绑定模型值呢?这是普伦克http://plnkr.co/edit/QYqfEVaQF8WmUvB1aHB6?p=preview
附加信息:
haschild 表示父元素具有子元素
例如:
1.人A拥有多个公司,所以人A有孩子
2.那么公司有一个有多个员工,那么该公司有孩子。所以在我的指令中,如果这个元素(假设这是元素 A)有子元素,那么生成子元素并输入并绑定到 ngModel。
我的答案:这就是我的想法和实现的简单方法http://plnkr.co/edit/olKb5oBoxv0utlNcBQPg?p=preview
var app = angular.module('plunk', []);
app.directive('generatePermissions', function($compile) {
return {
restrict : "E",
scope : true,
require : 'ngModel',
link:function(scope,element,attrs,ngModel)
{
function generatePermissionDom(parent,parentElement)
{
angular.forEach(scope.list,function(o,i){
if(parent.id==o.parentid)
{
var e = angular.element('<div style="border:1px solid red"><input type="checkbox" ng-model="list['+i+'].value"/></div>');
if(o.haschild)
generatePermissionDom(o,e);
parentElement.append(e);
}
});
}
angular.forEach(scope.list,function(o,i){
if(o.parentid == null)
{
var e = angular.element('<div style="border:1px solid red"><input type="checkbox" ng-model="list['+i+'].value"/></div>');
if(o.haschild)
generatePermissionDom(o,e);
element.append(e);
}
});
var p = $(element);
$compile(p.contents())(scope);
}
}
});
app.controller('MainCtrl', function($scope) {
$scope.list = [{"id":1,"name":"parent","value":true,"parentid":null,"haschild":true},{"id":2,"name":"id-1 child","value":false,"parentid":1,"haschild":true},{"id":3,"name":"id-2 child","value":false,"parentid":2,"haschild":true},{"id":4,"name":"id-3 child","value":false,"parentid":3,"haschild":false},{"id":5,"name":"id-1 child","value":false,"parentid":1,"haschild":true},{"id":6,"name":"id-5 child","value":false,"parentid":5,"haschild":false}];
$scope.checkValue = function()
{
angular.forEach($scope.list,function(o,i){
console.log("id:"+o.id+" name:"+o.name+" value:"+o.value);
});
}
});
.html
<body ng-controller="MainCtrl">
<generate-permissions ng-model="list"></generate-permissions>
<button ng-click="checkValue()">check</button>
</body>
但是,我认为@NewDev的答案是正确的答案!
基本上,您要查找的是创建一个任意分层的 DOM 结构并将其绑定到某个相等的分层数据结构(或 ViewModel)。
你如何代表你的层次结构 - 我会把它留给你。对于这个问题来说,这不是必需的。
为简单起见,假设我们将层次结构建模为树结构:
$scope.tree = {n: "root", v: false,
c: [
{n: "L11", v: false, c: []},
{n: "L12", v: false, c: [
{n: "L21", v: true, c: [
{n: "L31", v: false, c:[]}
]}
]}
]};
然后你需要遍历这棵树并创建绑定到某个对象o
的 DOM 元素(请耐心等待):
<div><input ng-model="o.v">{{o.n}}</div>
然后,需要针对范围进行编译。但由于结构是任意的,因此可以为每个节点创建一个新的子作用域。
那么,什么是o
? o
将是我们将在为树的每个节点创建的每个子作用域上创建的对象。
因此,假设您有一个递归函数traverseTree
,1) 创建 DOM 元素,2) 针对此范围进行编译,3) 为每个子范围创建一个子范围。它可能看起来像这样:
function traverseTree(n, scope, parent){
var me = angular.element("<div><input type='checkbox' ng-model='o.v'>{{o.n}}</div>");
$compile(me)(scope);
parent.append(me);
for (var i = 0; i < n.c.length; i++) {
var c = n.c[i];
var childScope = scope.$new(true);
childScope.o = c; // set object "o" on the scope
traverseTree(c, childScope, me);
}
}
该指令的链接函数启动树遍历:
app.directive("tree", function($compile){
function traverseTree(n, scope, parent){
// as above
}
return {
restrict: "A",
scope: {
root: "=tree"
},
link: function(scope, element, attrs){
var childScope = scope.$new(true);
childScope.o = scope.root;
traverseTree(scope.root, childScope, element);
}
};
});
用法是:
<div tree="tree"></div>
这是一个笨蛋
抱歉我刚刚看到,所以这是我的 2 便士,为了大家的利益。
若
$scope.tree = {n: "root", v: false,
c: [
{n: "L11", v: false, c: []},
{n: "L12", v: false, c: [
{n: "L21", v: true, c: [
{n: "L31", v: false, c:[]}
]}
]}
]};
我们可以做到
<script type="text/ng-template" id="Tree">
<input type='checkbox' ng-model='o.v'>{{o.n}}
<p ng-if="o.c">
<p ng-repeat="o in o.c" ng-include="'Tree'"></p>
</p>
</script>
<div>
<p ng-repeat="o in tree" ng-include="'Tree'"></p>
</div>
抱歉,没有测试此代码段没有时间,但这是无需在分层结构上编码即可工作的方式。已经用过很多次了。