【问题标题】:Removing child components programmatically through the parent component通过父组件以编程方式移除子组件
【发布时间】:2016-12-02 11:56:58
【问题描述】:

我想知道是否可以在 Angular 2 中执行以下操作。使用此模板的组件(例如):

父组件模板

<div>
  <childOne></childOne>

  <childTwo *ngFor="let item of items">
    whatever
  </childTwo>
</div>

有没有办法使用 ParentComponent 中的 ViewContainerRef 删除这些项目,如下所示?

var viewContainerRef = /* get ParentComponent ViewContainerRef */
var index = viewContainerRef.indexOf(childViewRef);
viewContainerRef.remove(index);

我尝试使用类似于此处提出的解决方案来检索子 ViewRef: Angular2 , How to find index of a view inside a viewContianer

但是 indexOf 返回 -1,好像容器中不存在子 ViewRef。

我想在 ParentComponent 之外删除这些子组件,而不是在 ParentComponent 代码中,例如从 items 数组中删除或通过绑定。

我也尝试使用渲染器中的 destroyView 方法,但没有效果。 NgFor 正在遍历 items 数组并为每个 childTwo 创建嵌入式视图,如果在这种情况下,从 ChildTwo 注入器(如链接解决方案中提出的)获得的 ViewRef 与这些 EmbeddedViewRef 相同,我不这样做。

有什么办法可以做这样的事情吗?

谢谢。

**************************** 更新 *********************** ****

我会尽量简化我想要实现的目标。我正在开发一个仪表板,用户可以在其中使用如下 API 创建其组件:

@Component({ selector: 'child' })
class UserChildComponent extends DashboardComponent {
  (...)
}

@Component({ selector: 'parent' })
class UserParentComponent extends DashboardComponent {

  @ViewChildren(UserChildComponent) m_children: QueryList<UserChildComponent>;

  private models: Array<ChildModel>;

  (...)
}

/* UserParentComponent template
<div>
  <child></child>
  <child *ngFor="let model of models"></child>
</div>

我有一个所有仪表板组件及其相互关系(父/子)的逻辑树,因为这里不涉及子类型和其他内容。

这是我正在考虑的场景:用户将能够删除任何这些子仪表板组件。我想拥有所有需要的关系树,从父级中删除子级并通知用户(可能通过父级中的 ViewChildren)。或者我实际上可以在父级上调用一个方法,以便用户可以更新其模型数组,这可能是最好的方法。

我只是在想一种方法,让用户可以减少工作量,而不必担心同步模型\组件(在这种情况下)

再次感谢。

【问题讨论】:

  • 您实际上想要完成什么?您要删除什么元素或组件,为什么?
  • 没错,因为删除元素通常是 Angular 通过指令完成的工作
  • 我希望能够从外部移除组件的任何子组件。 @GünterZöchbauer,我想要一种通用的方法来从外部的任何父组件中删除任何子组件。这将是实现我想要的最佳方式。
  • stackoverflow.com/questions/36325212/… 中演示的方法怎么样,用户只需要更新模型而不必担心同步 DOM。这就是Angular2中通常的做法。
  • @Daniel,Angular 旨在通过数据操作 DOM。这是错误的方法,因为您试图在不更改数据的情况下直接操作 DOM。即使你实现了这个包装器,它也不会改变这种情况——你只是将 DOM 操作委托给另一个仍然违背 Angular 意识形态的组件。所以我推荐的是:a)从数组中删除项目,剩下的由 Angular 完成; b) 需要删除的另一个组件包含在带有标志的 *ngIf 中 - 您的方法还需要显式放置自定义指令,因此请先使用标准指令。

标签: angular web-component


【解决方案1】:

你可以使用

let element = querySelector(...);
element.parentNode.removeChild(element)

但不鼓励在 Angular2 中使用直接 DOM 访问。 Angular2 本身并没有提供你想要的 API。 在 Angular2 中,您应该只更新模型并让 Angular 进行 DOM 操作。

【讨论】:

  • 是的,我想避免直接使用 DOM,正因为如此。另外,这样做会调用已删除组件的 ngOnDestroy 吗?谢谢,甘特!
  • 为什么不希望它在删除时被销毁?
  • 其实我是想被叫的。 ;) 只是在直接从 DOM 中删除它时确认它是否真的被调用了。谢谢,但我将不得不找到另一种不使用 DOM 操作的方法。 :(
  • 在不知道您的确切用例的情况下,这听起来很像您根本不应该做的事情。也许如果你能分享一些关于你实际尝试完成的事情的信息,我也许可以提供一些指导。
  • 嗯,这可能行得通,但你不妨使用 JQuery。
【解决方案2】:

我能想到的一个可能的解决方案是创建一个具有如下事件发射器的服务:

export class ChildRemoveNotifierService{

     public $remove = new EventEmitter<string>();

}

然后,我们需要一个可以删除元素并同时创建它们的指令:

 @Directive({ selector: '[remover]' })
export class RemoveDirective {

  @Input remove = '';
  constructor(
    private removerService:ChildRemoveNotifierService ,
    private _templateRef: TemplateRef,
    private _viewContainer: ViewContainerRef
    ) {


          let subscription =
          this.removerService.$remove.subscribe((tobeRemoved)=>{
             if(tobeRemoved===this.remove){
                 this._viewContainer.clear();
                 subscription.unsubscribe();
             }
          })
    }

然后,你会像这样使用它:

 <span *remover='my-component'>
     <my-component></my-component>
 </span>

基本上,任何需要动态移除的组件,都应该被 *remover 指令包裹。

然后,现在,everyOne 可以删除所有人 :)

你的父组件可以触发这样的事件:

export class ParentComponentOrAnyOther{

     constructor(private removerService:ChildRemoveNotifierService){

      }

      removeAComponent(){

          removerService.$remove.emit('my-component');

      }
}

这并不理想,或者可能是,我不知道。

但我知道这绝对是 Angular 的方式,而且你没有做任何 DOM 操作。

这样,你就拥有了 Angular2 的所有生命周期,特别是 onDestroy 事件将在 my-component 中触发。

编辑:

我认为这也可以:

  <my-component *remover='my-component'></my-component>

【讨论】:

  • 这确实是一种有趣的方法。将可移动组件包装在另一个元素中。如果我理解正确,在您的示例中,当孩子被移除时,总会有一个 元素剩余。并不是说这太令人担心了。感谢您写这篇文章的麻烦。 :)
  • 是的,这就是为什么我说它可能不是绝对好,但问题是如果您不自己动态加载组件并让Angular2正常加载它,您将无法销毁它
  • 实际上,我认为您也可以将 *remove 放在 my-component 本身上!!! ,我认为不会有任何跨度了
  • 为什么不直接使用 ngIf?
  • -ngIf 仅在您可以直接访问将其设置为 true 或 false 的变量时才有效,因此如果您想从父组件中创建 ngIf false 可能会很困难。 -ngIf 如果它是 true 将创建组件,这个问题不想要这个。 - 这样,即使指令也可以触发事件以删除其他组件。 -他可能需要在指令中添加更多内容。 - 整个订阅想法不适用于 ngIf ,除非拥有 ngIf 的组件会订阅如果您在一个组件中有多个 ngIf 时难以跟踪的内容
猜你喜欢
  • 2016-05-26
  • 2021-11-20
  • 2021-08-26
  • 2015-08-30
  • 2020-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多