AngularJS:如何创建 DOM 并绑定到基于任意分层数据的模型 [英] AngularJS : how to create DOM and bind to a model based on arbitrary hierarchical data

查看:19
本文介绍了AngularJS:如何创建 DOM 并绑定到基于任意分层数据的模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Angularjs:ng-repeat 中的复杂指令,如何绑定指令中的 ngModel 或 ngChecked 并使其工作?给定数组:

+----+-----------+---------+----------+-------+|身份证 |姓名 |父母 |子子|价值 |+----+-----------+---------+---------+-------+|1 |家长 |空|假|真实||2 |id1 孩子 |1 |真实|真实||3 |id2 孩子 |2 |真实|真实||4 |id3 孩子 |3 |假|真实||5 |id1 孩子 |1 |真实|真实||6 |id5 孩子 |5 |假|真实|+----+-----------+---------+---------+-------+$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 权限" ng-if="x.parentid == undefined" has-child="{{x}}"></div>

和指令

myApp.directive('hasChild', function($compile) {返回函数(范围,元素,属性){var j = JSON.parse(attrs.hasChild);函数 generatePermissionDom(thisElement,thisParent){angular.forEach(scope.permission,function(o,i){如果(thisParent.id==o.parentid){var e = $('<div><input type="checkbox" ng-model="o.value"/>'+o.name+'</div>');generatePermissionDom(e,o);$(thisElement).append(e);}});}如果(j.haschild)angular.forEach(scope.permission,function(o,i){如果(o.parentid==j.id){var e = $('<div><input type="checkbox" ng-model="o.value"/>'+o.name+'</div>');如果(o.haschild)generatePermissionDom(e,o);$(element).append(e);}});var p = $(元素);$compile(element.contents())(scope);}});

那么如何在指令中绑定模型值呢?这是plunkerhttp://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) {返回 {限制:E",范围:真实,要求:'ngModel',链接:功能(范围,元素,属性,ngModel){函数 generatePermissionDom(parent,parentElement){angular.forEach(scope.list,function(o,i){如果(parent.id==o.parentid){var e = angular.element('<div style="border:1px solid red"><input type="checkbox" ng-model="list['+i+'].value"/></div>');如果(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>');如果(o.haschild)generatePermissionDom(o,e);element.append(e);}});var p = $(元素);$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

 <generate-permissions ng-model="list"></generate-permissions><button ng-click="checkValue()">check</button>

但是,我认为@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(请耐心等待):

{{o.n}}

然后,这需要针对范围进行编译.但由于结构是任意的,您可以为每个节点创建一个新的子作用域.

那么,什么是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;//在作用域上设置对象o"traverseTree(c, childScope, me);}}

指令的链接函数开始遍历树:

app.directive("tree", function($compile){函数遍历树(n,范围,父){//如上}返回 {限制:A",范围: {根:=树"},链接:功能(范围,元素,属性){var childScope = scope.$new(true);childScope.o = scope.root;traverseTree(scope.root, childScope, element);}};});

用法是:

<div tree="tree"></div>

这是一个 plunker

Angularjs: complex directive in ng-repeat, how to bind the ngModel or ngChecked in directive and make it work? given the array:

+----+-----------+----------+----------+-------+
| 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}
];

so in html

<div ng-repeat="x in permission" ng-if="x.parentid == undefined"  has-child="{{x}}"></div>

and the directive

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

So how to bind the model value in the directive? here is the plunker http://plnkr.co/edit/QYqfEVaQF8WmUvB1aHB6?p=preview

additional info:

the haschild represent the the parent has child element

for example:

1.people A own multiple company, so the people A has child

2.then one of the company has multiple employee, then that company has child. so in my directive, if this element(assume this is element A) has child then generate the child element and input and bind to the ngModel.

My Answer: this is how i think and simple way to achieve 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>

however, i think @NewDev's answer is the correct answer!

解决方案

Basically, what you are looking for is to create an arbitrary hierarchical DOM structure and bind it to some equal hierarchical data structure (or ViewModel).

How you represent your hierarchy - I'll leave it up to you. It's not essential for the question.

For simplicity, suppose we model the hierarchy as a tree structure:

$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:[]}
            ]}
          ]}
        ]};

You then need to traverse this tree and create DOM elements bound to some object o (bear with me):

<div><input ng-model="o.v">{{o.n}}</div>

Then, this needs to be compiled against a scope. But since the structure is arbitrary, you could create a new child scope for each node.

So, what is o? o will be the object we will create on each child scope created for each node of the tree.

So, suppose you have a recursive function traverseTree, that 1) creates the DOM element, 2) compiles against this scope, and 3) creates a child scope for each child. It could look like something as follows:

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

The directive's link function kicks off the tree traversal:

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

});

The usage is:

<div tree="tree"></div>

Here's a plunker

这篇关于AngularJS:如何创建 DOM 并绑定到基于任意分层数据的模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆