简体   繁体   English

当递归地重复ng-repeat时,如何在ng-include中获取父元素

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

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. 我做了一个递归的ng-repeat元素,并试图操纵事物变成了一场噩梦,因为我没有引用我正在迭代的父。

The ng-repeat looks like this: ng-repeat看起来像这样:

ng-repeat="(key, value) in value"

Remember It's recursive, so each value in value becomes the new value, so I can't just use the "in" value from ng-repeat. 记住它是递归的,因此值中的每个值都成为新值,因此我不能只使用ng-repeat中的“in”值。 I want to do such things as checking if the parent is an array, but $parent is some weird thing, not the parent element of the current iteration value. 我想做的事情是检查父是否是一个数组,但是$ parent是一些奇怪的东西,而不是当前迭代值的父元素。

Some examples of things I want to do is: 我想要做的一些事情的例子是:

ng-show="isArray(parent)"
ng-click="delete(parent, $index)"

(as an example of what I'm doing as a work around, I've had to add an ___ISARRAYELEMENT___ property to each of my array elements, just to know that it's in an array >.>;;) (作为我正在做的工作的一个例子,我必须为每个数组元素添加一个___ISARRAYELEMENT___属性,只是为了知道它在一个数组中>。> ;;)

EDIT: Basically I want to know if there is any convenient meta data in an ng-repeat context that I'm missing. 编辑:基本上我想知道在我重复的ng-repeat上下文中是否有任何方便的元数据。

EDIT: Ok here is the html in it's entirety: 编辑:好的,这里的html是完整的:

<html ng-app>
<head>
    <title>JSON CRUD</title>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js"></script>
    <script src="angularjsoncrud.js"></script>
    <script type="text/ng-template" id="node.html">
        <button ng-click="minimized = !minimized" ng-show="!isLeaf(value)" ng-init="minimized=false" ng-class="{'glyphicon glyphicon-plus': minimized, 'glyphicon glyphicon-minus': !minimized}">-</button>
        <input ng-model="value.___KEY___" ng-if="!isArrayElement(value)" />
        <input ng-if="isLeaf(value)" ng-model="value.___VALUE___" />
        <ul ng-if="!isLeaf(value)" ng-show="!minimized">
            <li ng-repeat="(key,value) in value" ng-if="key != '___KEY___' && key != '___ISARRAY___'" ng-include="'node.html'"></li>
            <button type="button" ng-if="isArray(value)" ng-click="addToArray(value)">Add Element</button>
        </ul>
    </script>
</head>
<body ng-app="Application" ng-controller="jsoncrudctrl">
    <ul>
        <li ng-repeat="(key,value) in json" ng-include="'node.html'"></li>
    </ul>
    <pre>{{stringify(json)}}</pre>
</body>
</html>

One thing I would like to do is replace isArrayElement(value) with isArray(parent), because isArrayElement relies on meta data I added to the array, which I would prefer to not have to add. 我想做的一件事是用isArray(parent)替换isArrayElement(value),因为isArrayElement依赖于我添加到数组的元数据,我宁愿不必添加。

ng-repeat creates a new scope for each element. ng-repeat为每个元素创建一个新范围。
ng-include also creates a new scope. ng-include还会创建一个新范围。

When you use ng-include together with ng-repeat , there are 2 scopes created for each element: ng-includeng-repeat一起使用时,为每个元素创建了两个范围:

  • Scope created by ng-repeat for current element. ng-repeat为当前元素创建的范围。 This scope holds the current element in the iteration. 此范围保存迭代中的当前元素。
  • Child scope created by ng-include which inherits from ng-repeat 's created scope. ng-include创建的子范围 ,它继承ng-repeat的创建范围。

The $parent property of current scope allows you to access its parent scope. 当前作用域的$parent属性允许您访问其父作用域。

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 . 从本质上讲, ng-include创建的范围是空的,当您在node.html访问valuekey时,它实际上访问了ng-repeat创建的父范围中的继承值

In your node.html, accessing {{value}} is actually the same as {{$parent.value}} . 在您的node.html中,访问{{value}}实际上与{{$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}} 因此,如果您需要访问当前元素的父元素,则必须通过访问{{$parent.$parent.value}}

This DEMO will clear things up: 这个DEMO将清理:

    <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 . 如果您需要简化访问父级的方式,可以尝试使用ng-include onload初始化父ng-include Like this: 像这样:

In your top level, there is no ng-if => only 2 level deep 在您的顶级,没有ng-if =>只有2级深度

<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: 在您的子级别中,有ng-if => 3级别:

    <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. 在模板内部,您可以使用parent ,祖父母使用parent.parent访问parent ,依此类推。

DEMO DEMO

I would stay away from Angular's $parent and all the $scope creation and inheritance madness. 我会远离Angular的$parent和所有$scope创建和继承疯狂。 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 . 你需要的是保持对父对象的引用,而不是在ng-includeng-repeat之间找到多少范围,并且用$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 例如,如果要将父ng-repeat中的值公开给子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 然后在您的JavaScript代码中,您可以递归访问所有父项

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

Same code with ng-include 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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM