AngularJS :如何创建DOM并绑定到基于任意分层数据的模型

AngularJS : how to create DOM and bind to a model based on arbitrary hierarchical data

本文关键字:绑定 于任意 分层 模型 数据 DOM 何创建 创建 AngularJS      更新时间:2023-09-26

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>

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

那么,什么是oo将是我们将在为树的每个节点创建的每个子作用域上创建的对象。

因此,假设您有一个递归函数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>

抱歉,没有测试此代码段没有时间,但这是无需在分层结构上编码即可工作的方式。已经用过很多次了。