当在ng-repeat中迭代时,如何在ng-include中获取父元素

时间:2022-12-02 17:32:48

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. 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.

记住它是递归的,所以值中的每个值都变成了新的值,所以我不能只使用ng-repeat中的“in”值。我想检查父元素是否是数组,但是$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(父)替换isArrayElement(值),因为isArrayElement依赖于我添加到数组中的元数据,我宁愿不添加它。

2 个解决方案

#1


28  

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

ng-repeat为每个元素创建一个新的范围。ng-include还创建了一个新的范围。

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

当您使用ng-include和ng-repeat时,为每个元素创建了两个作用域:

  • Scope created by ng-repeat for current element. This scope holds the current element in the iteration.
  • 由ng-repeat创建的范围,用于当前元素。此范围保存迭代中的当前元素。
  • 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创建的范围是空的。它实际*问了由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}}

在你的节点。访问{{值}}的html实际上与{{$parent.value}相同。因此,如果您需要访问当前元素的父元素,则必须通过访问{{$parent.$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:

如果您需要简化访问父进程的方法,您可以尝试使用ng的onload初始化父进程。是这样的:

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.

在模板中,可以使用父类访问父类,使用父类访问祖父类。父母等等。

DEMO

演示

#2


3  

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

我会远离角的$parent和所有的$scope创建和继承的疯狂。您需要的是保持对父对象的引用,而不是发现在ng-include和ng-repeat之间有多少作用域,以及与$parent的杂费。我的建议是显式地保存对您感兴趣的值的引用,只需使用自定义逻辑实现它。例如,如果您想要从父元素中公开一个值,请重复使用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>

#1


28  

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

ng-repeat为每个元素创建一个新的范围。ng-include还创建了一个新的范围。

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

当您使用ng-include和ng-repeat时,为每个元素创建了两个作用域:

  • Scope created by ng-repeat for current element. This scope holds the current element in the iteration.
  • 由ng-repeat创建的范围,用于当前元素。此范围保存迭代中的当前元素。
  • 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创建的范围是空的。它实际*问了由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}}

在你的节点。访问{{值}}的html实际上与{{$parent.value}相同。因此,如果您需要访问当前元素的父元素,则必须通过访问{{$parent.$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:

如果您需要简化访问父进程的方法,您可以尝试使用ng的onload初始化父进程。是这样的:

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.

在模板中,可以使用父类访问父类,使用父类访问祖父类。父母等等。

DEMO

演示

#2


3  

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

我会远离角的$parent和所有的$scope创建和继承的疯狂。您需要的是保持对父对象的引用,而不是发现在ng-include和ng-repeat之间有多少作用域,以及与$parent的杂费。我的建议是显式地保存对您感兴趣的值的引用,只需使用自定义逻辑实现它。例如,如果您想要从父元素中公开一个值,请重复使用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>