将组件移动到Angular中的另一个父组件

时间:2017-07-13 01:02:26

标签: angular

这个问题是this question的Angular版本。

以下代码摘要总结了我的第一次尝试:

class NewParentComponent {

  constructor(elRef: ElementRef) {
    elRef.nativeElement.appendChild(myMovableElement);
    // where the reference to myMovableElement may come from a service.
  }
}

此尝试附带以下问题:

  1. 我们不应该直接在Angular中操作DOM。是以某种方式移动了Renderer可以实现的组件吗? (Ans:Per cgTag's answer,使用Renderer2)。
  2. 如果在移动子组件后原始父组件被销毁,则会在子组件上调用ngOnDestroy方法。
  3. 请参阅this Plunker演示此问题。这个Plunker建立在Angular Dynamic Component Loader example之上。打开浏览器控制台日志并注意“已销毁!”每次广告横幅更改时都会记录文字,即使是“拖我!”文本被拖入下拉框。

3 个答案:

答案 0 :(得分:10)

使用ViewContainerRef

可以将子组件从一个父组件移动到另一个组件
oldParentViewContainerRef.detach(index);
newParentViewContainerRef.insert(viewRef);

index是视图容器中子组件视图的索引。这可以通过以下方式获得:

let index = oldParentViewContainerRef.indexOf(viewRef);

viewRef对应于子组件的视图。据我所知,如果在ComponentFactoryResolver的帮助下以编程方式创建子组件,您只能暂停viewRef

let factory = componentFactoryResolver.resolveComponentFactory(MyChildComponentType);
let componentRef = oldParentViewContainerRef.createComponent(factory);
let viewRef = componentRef.hostView;

这里要说的是,如果您希望能够在不同的父组件之间移动组件,请确保以编程方式创建这些可移动组件,而不是静态地创建HTML。这为您提供了ViewRef个可移动组件的实例,它与ViewContainerRef很好地配合使用。

请参阅工作Plunker以获取示例。

答案 1 :(得分:4)

是的,您可以使用Renderer2类执行此操作,这是首选方法。使用该类的原因是为了使您的应用程序与Angular Universal保持兼容。

Angular没有像在AngularJS中那样耦合到DOM树。 Angular现在创建ViewRef个对象来处理组件和DOM之间的耦合。这意味着ViewRef使用的本机元素可以移动而不会破坏更改滞留树或注入树。

虽然Renderer2类在API方法中受到限制。它确实有你需要的方法。

abstract appendChild(parent: any, newChild: any): void;
abstract insertBefore(parent: any, newChild: any, refChild: any): void;
abstract removeChild(parent: any, oldChild: any): void;

我写了一个以windows为组件的UI库。这些窗口可以停靠在父窗口面板中。我能做到的唯一方法是移动组件的DOM元素。

我唯一关心的是组件的生命周期。当我的窗户破坏时,他们将这些元素移回原来的位置。我不知道如果元素是由另一个父元素从DOM中删除的话,是否会调用ngOnDestroy

答案 2 :(得分:1)

不建议操作DOM,但不一定错误。例如,复杂的UI组件几乎肯定需要直接操作DOM(例如,对话框和下拉的某些实现)。要避免的是泄漏,开发人员在没有角度的情况下操纵DOM,并且在不再需要操作之后无法清理DOM。

在DOM中移动组件时,我发现在包装器中移动组件最有帮助。例如,当我在模态组件中包含组件时,模态的父元素在嵌套在添加组件的级别的DOM中,并且模式的子元素被附加到body标签。当需要关闭模态时,对话框子元素将附加回包装器,将组件带回包装器中。