Angular2 在 onDestroy 之前分离视图?

Angular2 detach view before onDestroy?

在 Angular2 中是否有可能在组件被销毁之前得到通知!?即当它即将被销毁时。

我有一个容器组件,它的一个子组件上有一个 ViewContainerRef,它将用于动态加载视图。如果容器组件本身被销毁(在我的例子中是由于父组件中的 *ngFor 指令),我想分离当前加载到 ViewContainerRef 中的视图并将其再次附加到另一个容器上。

事情是:在 ngOnDestroy() 生命周期挂钩中,ViewContainerRef 已经被清除,因此所有视图都被销毁,没有任何东西可以分离了。

不确定是否有任何其他生命周期挂钩可以满足您的条件:

const LIFECYCLE_INTERFACES: Map<any, Type> = MapWrapper.createFromPairs([
  [LifecycleHooks.OnInit, OnInit],
  [LifecycleHooks.OnDestroy, OnDestroy],
  [LifecycleHooks.DoCheck, DoCheck],
  [LifecycleHooks.OnChanges, OnChanges],
  [LifecycleHooks.AfterContentInit, AfterContentInit],
  [LifecycleHooks.AfterContentChecked, AfterContentChecked],
  [LifecycleHooks.AfterViewInit, AfterViewInit],
  [LifecycleHooks.AfterViewChecked, AfterViewChecked],
]);

const LIFECYCLE_PROPS: Map<any, string> = MapWrapper.createFromPairs([
  [LifecycleHooks.OnInit, 'ngOnInit'],
  [LifecycleHooks.OnDestroy, 'ngOnDestroy'],
  [LifecycleHooks.DoCheck, 'ngDoCheck'],
  [LifecycleHooks.OnChanges, 'ngOnChanges'],
  [LifecycleHooks.AfterContentInit, 'ngAfterContentInit'],
  [LifecycleHooks.AfterContentChecked, 'ngAfterContentChecked'],
  [LifecycleHooks.AfterViewInit, 'ngAfterViewInit'],
  [LifecycleHooks.AfterViewChecked, 'ngAfterViewChecked'],
]);

也许您可以使用 OnChanges 钩子在迭代集合发生变化时得到通知,并且您预计视图会因 *ngFor.

而被销毁

然后使用 @ViewChildren 注释保存 *ngFor 中所有渲染组件的列表。类似于:

<my-component
    #mycomponents
    *ngFor="let c of collection"
</my-component>

您可以迭代由 #mycomponents 标识的组件,找出哪个已更改并调用一些自定义方法来分离您需要的任何内容。

另一个可能更简单的方法是只使用 @ViewChildrenQueryList 因为它有 属性 changes 这是一个 Observable<any> 所以订阅它应该通知您有关使用 *ngFor 迭代的集合的任何更改。但是,我不确定事件是在哪一点发出的,所以可能为时已晚,正如您在 onDestroy.

中描述的那样

我现在的解决方案(不是真正的解决方法)是实现使用 ngFor 指令的父组件的 ngOnChanges() 。如果由 ngFor 迭代的数组已经改变并且它的长度比以前更短,我只需分离所有容器的视图(@ViewChildren 容器:QueryList)并将它们映射到容器(Map)。 然后,我在 containers.changed 侦听器中通过迭代新容器列表并从地图加载 ViewRefs 再次重新插入映射视图。

@Component({
 selector: 'container-collection',
 directives: [Container],
 template: `<container *ngFor="let i of views"></container>`
})
export class ContainerCollection {
 public views = [];

 @ViewChildren(Container) private containers: QueryList<Container>;

 private viewMap = new Map<Container, ViewRef>();

 public ngOnChanges(changes: {[key: string]: SimpleChange]}): void {
  if(changes['views']) {
   //detach all views and remember which container had which view
   this.viewMap = new Map<Container, ViewRef>();

   this.containers.forEach(container => {
    var view = container.viewContainer.detach();
    if(view)
     this.viewMap.set(container, view);
   });
  }
 }

 public ngAfterViewInit(): void {
  //insert the views again (into the appropriate containers)
  this.containers.changes.subscribe( () => {
   this.containers.forEach(container => {
    var view = this.viewMap.get(container);
    if(view)
     container.viewContainer.insert(view);
   });
  });
 }
}

@Component({
 selector: 'container',
 template: `<div #viewContainer></div>`
})
export class Container {
 @ViewChild('viewContainer') public viewContainer;
}

该代码只是草稿,可能包含语法错误。但是这个想法(对我有用)应该很清楚。

Angular2 团队最好添加一个 LifeCycle 挂钩,该挂钩在组件实际销毁之前被调用。 (例如 ngBeforeDestroy() )左右。