How to put ng-repeat inside ng-repeat for n number of times

I have a JSON object having nested nodes, which can go on for any number of level. I need to display the content of a node on click of it's parent's node. It would look something like this enter image description here

     "node": [
    {
      "id": "id of the concept model",
      "name": "Curcumin",
      "type": "conceptmodel",
      "node": [
        {
          "id": "group1",
          "name": "Node 01",
          "weight": "70",
          "type": "text",
          "node": [
            {
              "id": "group11",
              "name": "Node 02",
              "weight": "70",
              "type": "structure",
              "node": []
            }
          ]
        }
      ]
    },
    {
      "id": "id of the concept model",
      "name": "Abuse Resistent Technology",
      "type": "conceptmodel",
      "node": [
        {
          "id": "group1",
          "name": "Category 01",
          "weight": "70",
          "type": "text",
          "node": []
        }
      ]
    },
    {
      "id": "id of the concept model",
      "name": "PC in Aviation",
      "type": "conceptmodel",
      "node": [
        {
          "id": "group1",
          "name": "Industry",
          "weight": "70",
          "type": "text",
          "node": [
             {
          "id": "group1",
          "name": "Node 01",
          "weight": "70",
          "type": "text",
          "node": []
            }
          ]
        }
      ]
    }
  ]

I have done something like this for two levels :

<div class="conceptModels">
   <!--tree starts-->
   <ul class="tree">
      <span class="treeBlk">
         <li ng-repeat="conceptModel in conceptModels.node" >
            <span ng-click="levelOne=true" class="textSpan show top">{{conceptModel.name}}<span class="arrclose"></span></span>
            <ul ng-show="levelOne">
               <li ng-repeat="node1 in conceptModel.node">
                  <span  ng-click="levelTwo=true" class="textSpan">{{node1.name}}<span class="arrclose"></span></span>
                  <ul ng-show="levelTwo">
                     <li ng-repeat="node2 in node1.node">
                        <span class="textSpan">{{node2.name}}<span class="arrclose"></span> </span>
                     </li>
                  </ul>
               </li>
            </ul>
         </li>
      </span>
   </ul>
</div>

Is there a way to generalize this solution to any number of level??

Answers:

Answer

Try This

var jimApp = angular.module("mainApp",  []);

jimApp.controller('mainCtrl', function($scope){
  $scope.nodes = [
        {
          "id": "id of the concept model",
          "name": "Curcumin",
          "type": "conceptmodel",
          "node": [
            {
              "id": "group1",
              "name": "Node 01",
              "weight": "70",
              "type": "text",
              "node": [
                {
                  "id": "group11",
                  "name": "Node 02",
                  "weight": "70",
                  "type": "structure",
                  "node": []
                }
              ]
            }
          ]
        },
        {
          "id": "id of the concept model",
          "name": "Abuse Resistent Technology",
          "type": "conceptmodel",
          "node": [
            {
              "id": "group1",
              "name": "Category 01",
              "weight": "70",
              "type": "text",
              "node": []
            }
          ]
        },
        {
          "id": "id of the concept model",
          "name": "PC in Aviation",
          "type": "conceptmodel",
          "node": [
            {
              "id": "group1",
              "name": "Industry",
              "weight": "70",
              "type": "text",
              "node": [
                 {
              "id": "group1",
              "name": "Node 01",
              "weight": "70",
              "type": "text",
              "node": []
                }
              ]
            }
          ]
        }
      ];
});
li{
  list-style: none;
  background-color:#334559;
  color:#FFF;
  padding:2px;
  cursor: pointer;
  
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.2/css/font-awesome.min.css" rel="stylesheet"/>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

    

    
<div ng-app="mainApp" ng-controller="mainCtrl">
  <script type="text/ng-template" id="treeNodes.html">
    <ul>
      <li ng-repeat="node in nodes" >
        <div ng-click="node.expand = (node.expand?false:true);" ><i class="fa" ng-class="{'fa-caret-right':(node.node.length && !node.expand), 'fa-caret-down':(node.node.length && node.expand)}"></i>&nbsp;{{node.name}}</div>
        <div ng-show="node.node.length && node.expand"  ng-include=" 'treeNodes.html' " onload="nodes = node.node"></div>
      </li>
    </ul>
                                                                                                 </script>
  <div ng-include=" 'treeNodes.html'" style="overflow-y: auto;height: 55%;width: 300px;"></div>
</div>

Answer

One of the solution can be to create a directive that takes care of recursive operation to any limit.

Note : This solution is a generic json printer + editor for angular that i created for one of my applications

JsonApp.directive('renderInput',['$compile','NODE_RELATION_CONFIG',function($compile){

    var getTemplate = function(inputKey,inputValue,inputParent,inputConfig,inputDisabled,inputHidden){
        var template = '';
        var disabled = (inputDisabled || (inputConfig && inputConfig["disabled"])) ? true : false;
        var hidden = (inputHidden || (inputConfig && inputConfig["hidden"])) ? true : false;

        if(typeof(inputConfig)=="undefined")
            inputConfig ={}

        for(var key in inputParent)
        {
            if(typeof(inputConfig[key])=="undefined")
                inputConfig[key] = {};
        }



        if(typeof(inputValue)=="object")
        {

            //template = '<div ng-hide="'+hidden+'" style="padding-left:7%;border:1px solid #ddd;"><div class="pheading">{[{ inputKey }]}</div><div id="render-123" ng-repeat="(key,value) in inputValue"  render-input input-key="{[{ key}]}" input-parent="inputValue" input-value="value" input-config="inputConfig[key]" input-disabled="'+disabled+'" input-hidden="'+hidden+'"></div></div>';
            template = '<div ng-hide="'+hidden+'"><div id="render-123" ng-repeat="(key,value) in inputValue"  render-input input-key="{[{ key}]}" input-parent="inputValue" input-value="value" input-config="inputConfig[key]" input-disabled="'+disabled+'" input-hidden="'+hidden+'"></div></div>';
        }
        else
        {

            var fieldHeading = (inputConfig && inputConfig["mapped_name"]) ? inputConfig["mapped_name"]: inputKey;
            if(typeof(inputValue)!="string" || inputValue.length < 200)
            {
                //small fields use input type text

                template = '<div ng-hide="'+hidden+'"><h3 class="gi-orange dy-field-title">'+fieldHeading+'</h3><input class="dy-id-input" type="text" value="{[{ inputValue }]}" ng-disabled="'+disabled+'" /></div>';


            }
            else
            {
                template = '<div ng-hide="'+hidden+'"><h3 class="gi-orange dy-field-title">'+fieldHeading+'</h3><textarea class="dy-id-textarea" type="text" ng-disabled="'+disabled+'">{[{ inputValue }]}</textarea></div>';
            }
        }
        return template
    }

    return{
        scope:{
            inputKey:"@",
            inputValue:"=",
            inputParent:"=",
            inputConfig:"=",
            inputDisabled:"=",
            inputHidden: "="
        },



        link : function(scope, element, attrs) {

            element.html(getTemplate(scope.inputKey,scope.inputValue,scope.inputParent,scope.inputConfig,scope.inputDisabled,scope.inputHidden)).show();

            $compile(element.contents())(scope);
            $(element).on('change','input,textarea',function(e){
                if(!scope.$$phase)
                    scope.inputParent[scope.inputKey]=$(this).val();
                if(!scope.$$phase)
                    scope.$apply();
                e.stopImmediatePropagation();
            })

        },

        restrict: 'AE'
    }
}]);

Sample Config :

{"flight_sector": {"additional_fields": ["at.scdl_pg.content", "at.scdl_pg.meta.keywords", "at.scdl_pg.meta.title", "at.scdl_pg.meta.desc"], "fields_mapped_names": {"at|scdl_pg|meta|desc": "Flight Sector Page : Meta Description", "at|scdl_pg|meta|keywords": "Flight Sector Page : Meta Keywords", "at|score|flier": "Flight Sector Flier Score", "at|scdl_pg|content": "Flight Sector Page : Content Html", "at|scdl_pg|meta|title": "Flight Sector Page : Meta Title", "at|type": "Flight Sector Type"}, "disabled_fields": ["at.score.flier", "at.type"], "hidden_fields": ["at.airlines", "_id", "s", "e", "sn", "en", "st", "t"], "settings": {"en": {"hidden": 1}, "e": {"hidden": 1}, "st": {"hidden": 1}, "s": {"hidden": 1}, "at": {"scdl_pg": {"content": {"mapped_name": "Flight Sector Page : Content Html"}, "meta": {"keywords": {"mapped_name": "Flight Sector Page : Meta Keywords"}, "title": {"mapped_name": "Flight Sector Page : Meta Title"}, "desc": {"mapped_name": "Flight Sector Page : Meta Description"}}}, "score": {"flier": {"disabled": 1, "mapped_name": "Flight Sector Flier Score"}}, "type": {"disabled": 1, "mapped_name": "Flight Sector Type"}, "airlines": {"hidden": 1}}, "t": {"hidden": 1}, "_id": {"hidden": 1}, "sn": {"hidden": 1}}}, "routes_map": {"additional_fields": ["at.rpr_pg.desc"], "fields_mapped_names": {"at|rpr_pg|desc": "Routeplanner Page Write-Up"}, "hidden_fields": ["routes", "t", "s", "e", "sn", "en", "_id"], "settings": {"en": {"hidden": 1}, "e": {"hidden": 1}, "s": {"hidden": 1}, "t": {"hidden": 1}, "routes": {"hidden": 1}, "_id": {"hidden": 1}, "at": {"rpr_pg": {"desc": {"mapped_name": "Routeplanner Page Write-Up"}}}, "sn": {"hidden": 1}}}}

Note: This sample config takes care of the additional fields you want to add to existing json + if you want to hide few fields specifically + keep some fields disabled as input fields.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.