AngularJS :如何创建 DOM 并绑定到基于任意分层数据的模型
AngularJS : how to create DOM and bind to a model based on arbitrary hierarchical data
Angularjs:ng-repeat 中的复杂指令,如何绑定 ngModel 或 ngChecked in 指令并使其工作?
给定数组:
+----+-----------+----------+----------+-------+
| 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
补充信息:
有child表示parent有child个元素
例如:
1.people A拥有多家公司,所以A人有child
2.then其中一家公司有多名员工,那么那家公司有child。
所以在我的指令中,如果此元素(假设这是元素 A)具有 child,则生成 child 元素并输入并绑定到 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:[]}
]}
]}
]};
然后您需要遍历这棵树并创建 DOM 个绑定到某个对象的元素 o
(请耐心等待):
<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);
}
}
指令的 link 函数启动树遍历:
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>
这是一个plunker
很抱歉我刚刚看到所以这是我的 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>
抱歉没有时间测试此代码段,但这是无需在分层结构上编码即可工作的方式。用过很多次了
Angularjs:ng-repeat 中的复杂指令,如何绑定 ngModel 或 ngChecked in 指令并使其工作? 给定数组:
+----+-----------+----------+----------+-------+
| 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
补充信息:
有child表示parent有child个元素
例如:
1.people A拥有多家公司,所以A人有child
2.then其中一家公司有多名员工,那么那家公司有child。 所以在我的指令中,如果此元素(假设这是元素 A)具有 child,则生成 child 元素并输入并绑定到 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:[]}
]}
]}
]};
然后您需要遍历这棵树并创建 DOM 个绑定到某个对象的元素 o
(请耐心等待):
<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);
}
}
指令的 link 函数启动树遍历:
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>
这是一个plunker
很抱歉我刚刚看到所以这是我的 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>
抱歉没有时间测试此代码段,但这是无需在分层结构上编码即可工作的方式。用过很多次了