【问题标题】:Angular - Toggle child with unlimited nestingAngular - 无限嵌套切换孩子
【发布时间】:2019-12-17 21:19:31
【问题描述】:

我有一个数组,它可以包含未知数量的项目和无限嵌套。我需要能够为每个父级添加一个按钮来切换子级的显示,并且每个子级都可以有一个按钮来切换其子级。此外,每个孩子都有一个可以关闭父母的按钮。

我无法让开关正常工作。我现在拥有它的方式是基于数组的索引,对于每组子元素,它从 0 开始,如果它们具有相同的索引,这可能会导致多个项目同时打开。

我在这里有一个关于 Stackblitz 问题的示例:https://stackblitz.com/edit/angular-nested-menu-toggle?file=src%2Fapp%2Fapp.component.html

您可以通过单击按钮“five”,然后单击“five.two”按钮来查看问题。您可以看到它同时打开“five.two”以及“two”和“two.two”,因为它们都具有相同的索引。

所以我需要的是能够切换一个项目,它只影响它的直接父或子,而不是同时影响其他所有东西。

这是我的数组:

myArray = [
  {
    'title': 'one'
  },
  {
    'title': 'two',
    'children': [
      {
        'title': 'two.one'
      },
      {
        'title': 'two.two',
        'children': [
          {
            'title': 'two.two.one'
          },
          {
            'title': 'two.two.two'
          }
        ]
      },
      {
        'title': 'two.three',
        'children': [
          {
            'title': 'two.three.one'
          },
          {
            'title': 'two.three.two'
          }
        ]
      }
    ]
  },
  {
    'title': 'three',
    'children': [
      {
        'title': 'three.one'
      },
      {
        'title': 'three.two',
        'children': [
          {
            'title': 'three.two.one'
          },
          {
            'title': 'three.two.two'
          }
        ]
      },
      {
        'title': 'three.three',
        'children': [
          {
            'title': 'three.three.one'
          },
          {
            'title': 'three.three.two'
          }
        ]
      }
    ]
  },
  {
    'title': 'four'
  },
  {
    'title': 'five',
    'children': [
      {
        'title': 'five.one'
      },
      {
        'title': 'five.two'
      }
    ]
  },
  {
    'title': 'six',
    'children': [
      {
        'title': 'six.one'
      },
      {
        'title': 'six.two',
        'children': [
          {
            'title': 'six.two.one'
          },
          {
            'title': 'six.two.two'
          }
        ]
      },
      {
        'title': 'six.three',
        'children': [
          {
            'title': 'six.three.one'
          },
          {
            'title': 'six.three.two'
          }
        ]
      }
    ]
  }
];

然后我在构造函数中有一个切换变量:

constructor() {
  this.toggle = this.myArray.map(i => false);
}

最后,我的 HTML

<ul>
  <li *ngFor="let item of myArray; let i = index">
    <button (click)="toggle[i] = !toggle[i]">{{item.title}}</button>
    <div *ngIf="item.children && toggle[i]">
      <ng-container *ngTemplateOutlet="tree; context: { $implicit: item.children, idx: i }"></ng-container>
    </div>
  </li>
</ul>

<ng-template #tree let-allItems let-idx="idx">
  <ul>
    <li *ngFor="let item of allItems; let n = index">
      <button (click)="toggle[idx] = !toggle[idx]">X</button>
      <button (click)="toggle[n] = !toggle[n]">{{item.title}}</button>
      <div *ngIf="item.children && toggle[n]">
        <ng-container *ngTemplateOutlet="tree; context: { $implicit: item.children, idx: n }"></ng-container>
      </div>
    </li>
  </ul>
</ng-template>

谢谢!

【问题讨论】:

    标签: angular


    【解决方案1】:

    一种可能的解决方案是创建普通的 javascript 对象:

    toggle: any = {};
    

    并利用组合索引来查看树中特定项目的状态,使其看起来像:

    正如您在上面看到的,所有索引都是唯一的。

    您需要做的一件事是传递正确的索引:

    <ul>
      <li *ngFor="let item of myArray; let i = index">
        <button (click)="toggle[i] = !toggle[i]">{{item.title }} - {{i}}</button>
        <div *ngIf="item.children && toggle[i]">
          <ng-container *ngTemplateOutlet="tree; context: { $implicit: item.children, idx: i }">
          </ng-container>
        </div>
      </li>
    </ul>
    
    <ng-template #tree let-allItems let-idx="idx">
      <ul>
        <li *ngFor="let item of allItems; let n = index">
          <button (click)="toggle[idx] = !toggle[idx]">X - {{idx}}</button>
                                  ^^^^
                               Parent index
          <button (click)="toggle[idx + '.' + n] = !toggle[idx + '.' + n]">{{item.title}} - {{ idx + '.' + n}}</button>
                                  ^^^^^^^^^^^^^
                                   Child index
          <div *ngIf="item.children && toggle[idx + '.' + n]">
            <ng-container 
              *ngTemplateOutlet="tree; context: { $implicit: item.children, idx: idx + '.' + n }"></ng-container>
                                                                                 ^^^^^^^^^^^^^
                                                               Child index becomes parent in next iteration
          </div>
        </li>
      </ul>
    </ng-template>
    

    注意我是如何产生新索引的

    idx + '.' + n
    

    Stackblitz Example

    【讨论】:

      【解决方案2】:

      制作一个接收项目作为输入的项目组件。现在每个项目只对自己负责。组件模板应该是这样的:

      <p>
        <span>{{item.title}}</span>
        <button *ngIf="hasChildren" type="button" class="toggleBtn" (click)="toggleChildren()">Toggle Children</button>
        <button *ngIf="hasParent" type="button" class="toggleBtn" (click)="toggleParent()">Toggle Parent</button>
      </p>
      
      
      <ul *ngIf="areChildrenOpen">
        <li *ngFor="let child of item.children">
          <app-item [item]="child" [hasParent]="true" (toggleClicked)="toggleChildren()"></app-item>
        </li>
      </ul>
      

      这是一种更简洁的处理方式。

      A full Stackblitz example

      【讨论】:

        【解决方案3】:

        我实现了递归树的基本解决方案,如下所示;

        诀窍是在父模板中定义变量并将其用于所有子模板。如果单击父模板,然后将 showChilds 变量更改为反转,那么所有子模板将被隐藏或显示。

        <ng-container *ngTemplateOutlet="tree; context: { $implicit: myArray, idx: 1  , isChildOpen = false   }">
        </ng-container>
            
        
            <ng-template #tree let-allItems let-idx="idx" let-showChilds="isChildOpen">
              <ul>
                <li *ngFor="let item of allItems; let n = index">
                  <button (click)="showChilds = !showChilds">X - {{idx}}</button>
                                     
                                       Parent index
                  <button (click)="showChilds = !showChilds">{{item.title}} - {{ idx + '.' + n}}</button>
                                           Child index
                  <div *ngIf="item.children && showChilds">
                    <ng-container 
                      *ngTemplateOutlet="tree; context: { $implicit: item.children, idx: idx + '.' + n, isChildOpen:showChilds  }"></ng-container>
                                                                                         
                                                                       Child index becomes parent in next iteration
                  </div>
                </li>
              </ul>
            </ng-template>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-12-13
          • 2018-05-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-05
          • 1970-01-01
          相关资源
          最近更新 更多