How to get parent element inside ng-include when iterating in ng-repeat recursively

后端 未结 2 1092
轻奢々
轻奢々 2021-02-02 18:17

I made a recursive ng-repeat element, and trying to manipulate things has turned into a nightmare, because I don\'t have reference to the parent I\'m iterating over.

The

相关标签:
2条回答
  • 2021-02-02 18:27

    I would stay away from Angular's $parent and all the $scope creation and inheritance madness. What you need is to keep a reference to the parent object, not finding how many scopes are in-between ng-include's and ng-repeat's and juggling with $parent.$parent. My suggestion is to explicitly save references to the values you are interested in, just implement it yourself with custom logic. For example, if you want to expose a value from the parent ng-repeat to the child ng-repeat

    <!-- Explictly save the value into the parent var -->
    <div ng-init="parent = value">
      <!-- Save parent reference and
           update the parent var to point to the new value -->
      <div ng-repeat="(k,value) in value"
           ng-init="value._parent = parent; parent = value;"> 
        <div ng-repeat="(k,value) in value"
             ng-init="value._parent = parent">
          <button ng-click="doSomething(value)"></button>
        </div>
      </div>
    </div>
    

    Then in your javascript code you can access all parents recursively

    function doSomething(value){
      parent1 = value._parent;
      parent2 = parent1._parent;
    }
    

    Same code with ng-include

    <div ng-init="parent = value">
      <div ng-repeat="(key,value) in value"
           ng-init="value._parent = parent; parent = value;"
           ng-include="'node.html'">
      </div>
    </div>
    
    <script type="text/ng-template" id="node.html">
      <div ng-if="!isLeaf(value)"
           ng-repeat="(key,value) in value"
           ng-init="value._parent = parent; parent = value;"
           ng-include="'node.html'"> 
    
      <button ng-if="isLeaf(value)" ng-click="doSomething(value)"></button>
    </script>
    
    0 讨论(0)
  • 2021-02-02 18:44

    ng-repeat creates a new scope for each element.
    ng-include also creates a new scope.

    When you use ng-include together with ng-repeat, there are 2 scopes created for each element:

    • Scope created by ng-repeat for current element. This scope holds the current element in the iteration.
    • Child scope created by ng-include which inherits from ng-repeat's created scope.

    The $parent property of current scope allows you to access its parent scope.

    Essentially, scope created by ng-include is empty, when you access value and key in your node.html, it actually access the inherited values from parent scope created by ng-repeat.

    In your node.html, accessing {{value}} is actually the same as {{$parent.value}}. Therefore if you need to access the parent of the current element, you have to do one step further by accessing {{$parent.$parent.value}}

    This DEMO will clear things up:

        <script type="text/ng-template" id="node.html">
            <div>
                Current: key = {{key}}, value = {{value}}
            </div>
            <div>
                Current (using $parent): key = {{$parent.key}}, value = {{$parent.value}}
            </div>
             <div>
                 Parent: key = {{$parent.$parent.key}}, value = {{$parent.$parent.value}}, isArray: {{isArray($parent.$parent.value)}}
            </div>
            <ul ng-if="isObject(value)"> //only iterate over object to avoid problems when iterating a string
    <li ng-repeat="(key,value) in value" ng-include="'node.html'"></li>            
            </ul>
        </script>
    

    If you need to simplify the way to access the parent, you could try initializing the parent using onload of ng-include. Like this:

    In your top level, there is no ng-if => only 2 level deep

    <ul>
        <li ng-repeat="(key,value) in json" 
         ng-include="'node.html'" onload="parent=$parent.$parent"></li>
    </ul>
    

    In your sub levels, there is ng-if => 3 levels deep:

        <ul ng-if="isObject(value)">
            <li ng-repeat="(key,value) in value" 
    ng-include="'node.html'" onload="parent=$parent.$parent.$parent"></li>            
        </ul>
    

    Inside the template, you could access the parent using parent, grandparent using parent.parent and so on.

    DEMO

    0 讨论(0)
提交回复
热议问题