我正在开发一个使用多标签布局的Angular 7应用程序。每个标签页包含一个组件,该组件可以引用其他嵌套组件。
当用户选择新的/另一个标签页时,当前标签页上显示的组件将被销毁(我不仅仅是隐藏它们,并且自从打开的标签页可能很多,这对我来说似乎是更快的解决方案)。由于加载组件可能很耗费时间(可能需要从API检索大量数据),因此我正在尝试在选项卡容器中保持每个组件状态(它将保持整个应用程序生命周期)。
一切都按预期工作,但我认为我已经使用了很多代码来满足我的需求,希望一切都能更简单(并且更少出错)。
下面是我如何实现它的摘录。首先,我创建了一个抽象类,每个选项卡中的组件都应该扩展该类。
当用户选择新的/另一个标签页时,当前标签页上显示的组件将被销毁(我不仅仅是隐藏它们,并且自从打开的标签页可能很多,这对我来说似乎是更快的解决方案)。由于加载组件可能很耗费时间(可能需要从API检索大量数据),因此我正在尝试在选项卡容器中保持每个组件状态(它将保持整个应用程序生命周期)。
一切都按预期工作,但我认为我已经使用了很多代码来满足我的需求,希望一切都能更简单(并且更少出错)。
下面是我如何实现它的摘录。首先,我创建了一个抽象类,每个选项卡中的组件都应该扩展该类。
export abstract class TabbedComponent implements OnInit, OnDestroy {
abstract get componentName(): string;
tab: LimsTab;
host: TabComponent;
private _componentInitialized = false;
constructor(
private _host: TabComponent,
) {
this.host = _host;
}
get componentInitialized(): boolean {
return this._componentInitialized;
}
ngOnInit(): void {
this.tab = this.host.tab;
this.loadDataContext();
this._componentInitialized = true;
}
ngOnDestroy(): void {
this.saveDataContext();
}
get dataContext() {
return this.tab.dataContext;
}
protected abstract saveDataContext(): void;
protected abstract loadDataContext(): void;
}
loadDataContext
和 saveDataContext
在具体组件中实现,包含保存/检索组件实例值的逻辑。此外,我使用了 _componentInitialized
来确定组件何时调用其生命周期钩子 OnInit:组件可以从其父组件接收 @Inputs,并且根据我所见,ngOnChanges
在 OnInit
之前触发。
以下是具体实现示例:
@Component({
...
})
export class MyComponent extends TabbedComponent implements OnChanges {
private qualityLotTests: QualityLotTestListItem[];
private _selectedTest: QualityLotTestListItem;
@Input()
selectedQualityLot: string;
@Output()
selectedTest: EventEmitter<QualityLotTestListItem> = new EventEmitter<QualityLotTestListItem>();
constructor(_host: TabComponent, private qualityLotService: QualityLotService) {
super(_host);
}
get componentName(): string {
return 'QualityLotTestListComponent';
}
ngOnChanges(changes: SimpleChanges): void {
if (this.componentInitialized) {
// before calling loadData I need to restore previous data (if any)
// this allow me to undestrand if loaded data filters has changed
// I know I restored it if onInit has executed
// if componentInitialized -> onInit has been executed and input parameters passed from parent are changed
this.loadData();
}
}
protected saveDataContext(): void {
this.dataContext[this.componentName].selectedQualityLot = this.selectedQualityLot;
this.dataContext[this.componentName].state = this.state;
this.dataContext[this.componentName].qualityLotTests = this.qualityLotTests;
this.dataContext[this.componentName].selectedSampleTestIDs
= this.selectedSampleTestIDs;
this.dataContext[this.componentName]._selectedTest = this._selectedTest;
}
protected loadDataContext(): void {
let previouslySelectedQualityLot: string;
if (this.dataContext[this.componentName]) {
previouslySelectedQualityLot = this.dataContext[this.componentName].selectedQualityLot;
this.state = this.dataContext[this.componentName].state || this.state;
this.qualityLotTests = this.dataContext[this.componentName].qualityLotTests;
this._selectedTest = this.dataContext[this.componentName]._selectedTest;
} else {
this.dataContext[this.componentName] = {};
}
this.selectedTest.emit(this._selectedTest);
if (this.qualityLotTests && previouslySelectedQualityLot === this.selectedQualityLot) {
this.dataStateChange(<DataStateChangeEvent>this.state);
} else {
this.loadData();
}
}
loadData(): void {
if (this.selectedQualityLot) {
this.loading = true;
this.qualityLotService
.getQualityLotTests(this.selectedQualityLot)
.subscribe(
qualityLotTests => {
this.qualityLotTests = qualityLotTests;
this.gridData = process(this.qualityLotTests, this.state);
this.loading = false;
},
error => (this.errorMessage = <any>error)
);
} else {
this.qualityLotTests = null;
this.gridData = null;
this.state = {
skip: 0,
take: 10
};
this.selectedSampleTestIDs = [];
this.selectedTest.emit(null);
}
}
public dataStateChange(state: DataStateChangeEvent): void {
this.loading = true;
this.state = state;
this.gridData = process(this.qualityLotTests, this.state);
this.loading = false;
}
}
您认为我如何改进上面的代码?
我在这里加载了我的应用程序的摘录 https://stackblitz.com/edit/angular-tabbed-app
localhost:4200/person/999'
在前往此组件的路上,根据路由参数进行数据获取,并检查数据是否存在于你的状态管理中(推荐使用redux,但类似服务的东西也可以)。如果不存在,则添加数据。 - favdev