组件销毁后,侦听器仍处于活动状态

时间:2019-07-18 10:00:50

标签: javascript angular

我遇到了与Angular生命周期挂钩相关的问题,因为触发了OnDestroy事件,并且我的组件似乎仍然具有其侦听器。

我有一个项目列表和每个项目的饼图,将它们悬停时会触发一个弹出窗口。该弹出窗口是由Angular Material材质制成的自定义组件,但它遵循类似组件的行为(例如mat-menu)。它具有一个onOpen侦听器,可在打开弹出窗口时触发。

这里的问题是,在应该销毁组件及其父对象之后,悬停仍然有效,这在每次重新加载项目列表时都会发生。

这是我的实现的简化版本:

// Table component
import { Component, OnInit, OnDestroy, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';
import { select, Store } from '@ngrx/store';
import { Project } from '@models';
import { projectsSelectors } from '@store/track';
import { Subscription } from 'rxjs';
import { Observable } from 'rxjs/Observable';

@Component({
	selector: 'app-projects-table',
	templateUrl: './projects-table.component.html',
	styleUrls: ['./projects-table.component.scss'],
	changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProjectsTableComponent implements OnInit, OnDestroy {
	projects$: Observable<Array<Project>>;
	projects: Array<Project>;
	subs = new Subscription();

	constructor(
		private store: Store<any>,
		private cd: ChangeDetectorRef,
	) {}

	ngOnInit() {
		this.projects$ = this.store.select(projectsSelectors.all);
 
		this.subs = this.projects$.subscribe((projects) => {
			this.projects = projects;
			this.cd.detectChanges();
		});

	}

	trackByFn(index, item) {
		return item.id;
	}

	ngOnDestroy() {
		this.subs.unsubscribe();
	}

}

// Pie component

import {
	ChangeDetectionStrategy,
	Component,
	Input,
	ViewChild,
	OnDestroy,
	OnInit,
} from '@angular/core';
import { PopoverPanel } from '@ng-components';
import {
	Project,
} from '@models';
import * as moment from 'moment';

@Component({
	selector: 'app-pie',
	templateUrl: './app-pie.component.html',
	styleUrls: ['./app-pie.component.scss'],
	changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PieComponent implements OnInit, OnDestroy {
	@Input() project: Project;
	@ViewChild('piePopover')
	budgetCompletionPopover: PopoverPanel;

	ngOnInit() {
    console.log('Init budget progress pie', this.budgetCompletionPopover);
	}

	ngOnDestroy() {
    console.log('Destroy pie');
	}
}


// Pie popover component

import { Component, Output, EventEmitter, Input, OnDestroy, OnInit } from '@angular/core';
import { PopoverPanelComponent } from '@ng-components';
import { Project } from '@/models';

@Component({
	selector: 'app-pie-popover',
	templateUrl: './pie-popover.component.html',
})
export class PiePopoverComponent extends PopoverPanelComponent implements OnInit, OnDestroy {
	@Input() project: IProject;
	@Output() close = new EventEmitter<void>();
	@Output() open = new EventEmitter<void>();

	constructor() {
		super();
		this.alignment = 'top';
		this.position = 'before';
		this.targetOffsetX = -84;
		this.triggerEvent = 'hover';
		this.overlapTrigger = true;
	}

	ngOnInit() {
    console.log('Init pie popover');
	}

	onOpen() {
    console.log('Opened pie popover', this.project.id);
	}

	ngOnDestroy() {
	    console.log('Destroy and close pie popover', this.project.id);
		this.close.emit();
	}
}
<!-- Pie Table Component -->

<table class="table">
	<app-projects-table-header class="table-head">
		<app-projects-table-filter></app-projects-table-filter>
	</app-projects-table-header>
	<tbody class="table-body">
    <tr *ngFor="let project of projects; trackBy: trackByFn">
      <app-pie [project]="project"></app-pie>
    </tr>
	</tbody>
</table>

<!-- Pie Component -->

<div class="container" [popoverTriggerFor]="piePopover">
	<ng-container>
    <!-- Project information displayed here -->
	</ng-container>
	<app-pie-chart
		class="graph-pie"
		[size]="55"
		[strokeWidth]="4"
		[progress]="completionRatio"
		[displayValue]="100 * completionRatio"
	>
	</app-pie-chart>
</div>

<app-pie-popover
	#piePopover
	[project]="project"
></app-pie-popover>

当项目重新加载时,我一直将鼠标悬停在饼上时,控制台输出:

  • 初始化馅饼
  • 初始饼图弹出框

悬停饼图

  • 打开饼图弹出框204

触发重新加载并回到悬停饼图

  • 销毁并关闭弹出窗口204
  • 销毁馅饼
  • 打开饼图弹出框204

我希望在应该避免显示问题的情况下完全破坏popover组件。 欢迎您提供任何线索,谢谢!

0 个答案:

没有答案