Angular 2:删除递归实例化的组件以某种方式创建新的组件实例

时间:2018-06-06 15:05:41

标签: angular typescript angular-services angular-components

正如标题所示,我有一个递归实例化的组件组。组件基于名为Item的树状数据模型,并通过递归调用模板并将模型的嵌套数组作为@Input()值传递,在嵌套列表中实例化。虽然这很好,但问题是操纵数据(存储在list.service.ts中)定义了此模板实例化的次数会导致某些错误。我有两个按钮连接到两个功能。一个删除特定项目并在项目树中向上移动剩余项目。这很好用。另一个按钮应该删除给定项目的项目数组中的所有项目,有效地删除其子项目。有趣的是,"删除和转移"函数只有在我的服务和组件使用主题和订阅时才能正常工作。虽然"删除孩子"如果我不使用订阅,函数似乎只能正常工作。相反,它似乎破坏了我点击的组件实例的组件实例"删除子项" (这不应该发生,因为我没有删除这个项目,只是它的项目数组),然后从根组件重建嵌套组件。

例如,如果我有以下嵌套项数组由DOM中的组件呈现:

  • 第1项
    • 第2项
      • 第3项
        • 第4项

然后我点击了第3项上的删除子项按钮,我希望为项目4调用onDestroy,保持项目1,2和3不变,但最终看起来像是这样:

  • 第1项
    • 第1项
      • 第2项
        • 第3项

我希望任何比我更了解Angular 2生命周期钩子的人是1)为什么订阅会阻止删除子项功能正常工作,2)为什么项目树得到每当我单击“删除子项”按钮时,从根节点重建,以及3)如何更改代码以解决此问题?

item.model.ts

export class Item{
  constructor(public id: number, public details: string, public date: Date, public items?: Item[]){}
}

项-list.component.html

<div *ngFor="let item of items">
    <ul>
      <li> {{item.details}}
        <br>
        <button (click)="onDelete(item.id)">Delete</button>
        <button (click)="onDeleteChildren(item.id)">
          Delete Children</button>
         <app-item-list [items]="item.items" *ngIf="item.items">
         </app-item-list>
      </li>
    </ul>
</div>

项-list.component.ts

  @Input() items: Item[] = [];
  listSubscription: Subscription;
  constructor(private list: ListService) {
    this.items = this.list.getItems();
    console.log('constructor called');
    this.listSubscription = this.list.listUpdated.subscribe(
      (items: Item[]) => {
        this.items = items;
      }
    );
  }

  onDelete(index: number) {
    this.list.deleteItemAndShiftChildren(index);
  }

  onDeleteChildren(index: number) {
    this.list.deleteChildItems(index);   
  }

list.service.ts

  deleteChildItems(index: number) {
    this.recursiveChildDelete(this.items, index);
    this.listUpdated.next(this.items.slice());
  }

  deleteItemAndShiftChildren(index: number) {
    this.recursiveChildShift(this.items, this.items[0], index);
    this.listUpdated.next(this.items.slice());
  }

  recursiveChildDelete(items: Item[], index: number) {
    items.forEach( element => {
      if (element.id === index) {
        if(element.items){
          element.items = [];
        }
      } else if (element.items) {
        this.recursiveChildDelete(element.items, index);
      }
    });
  }

  recursiveChildShift(items: Item[], oldItem: Item, index: number) {
    items.forEach( element => {
      // if the id of the element to be deleted is found
      if (element.id === index) {
      //if the deleted element is the root node
        if(oldItem==element){
          if(element.items){
            this.items = element.items;
            return;
          } else {
            this.items = [];
            return;
          }
        }
        oldItem.items = element.items;
        return;
      } else if (element.items) {
        oldItem = element;
        this.recursiveChildShift(element.items, oldItem, index);
      }
    });
  }

1 个答案:

答案 0 :(得分:0)

事实证明解决这个问题有两个关键:

1)我使用的样本数据没有正确使用。我的items数组中的两个项目的id值相同,这给我一个特定操作的奇怪错误。所以我解决了这个问题。

2)我创建了一个根组件,该组件持有对我的服务中的数组的订阅,该数组将其值传递给递归生成列表的子组件。这样我只有一个地方,即根,从服务主体接收更新,并从该根组件构建数组。我最初这样做的方式,我的每个组件都是组件树的一部分,在我的服务中订阅了Subject,这是错误的。