The issue I encountered involved a large component that loads over 1000 data elements, populated by a service called only once. Initially, the service was being called each time the component initialized, which seemed to be causing performance problems. To address this, I created a shared service that is invoked only once in a grandparent component.
The structure of the components is hierarchical:
- AddComponent (grandparent)
- Type1AddComponent
- BlockComponent (component with 1000+ data elements)
- Type2AddComponent
- BlockComponent
- Type3AddComponent
- BlockComponent
- Type1AddComponent
It's worth noting that the BlockComponent
is utilized in all three TypeComponents
. Despite a different title @Input, the displayed BlockComponent
data remains the same across the three TypeComponents
. While the initial loading of a TypeComponent
works fine, switching between them results in load times exceeding 3 seconds, which seems unreasonable. Is there a way to optimize load times?
I understand there is extensive code shared below. If possible, I would create a Plunker for a webpack project.
shared-data.service.ts
import { Injectable } from '@angular/core';
import { DataResolver } from '../../blocking/data/data.resolver';
import { Data } from 'si-data-model';
import { Observable } from 'rxjs/Observable';
import { Logger } from 'ngx-data-utils';
@Injectable()
export class DataService {
data: Data[] = []; // shared data
dataObs$: Observable<Data[]>;
logger: Logger;
completed = false; // used to signal whether the service has completed to components
constructor(private resolver: DataResolver,
logger: Logger) {
this.logger = logger;
}
ngOnInit() {
this.logger.debug('Data Service initialized.');
}
ngOnDestroy() {
this.logger.debug('Data Service destroyed.');
}
load() {
return this.resolver.resolve(); // retrieves the data elements from a web service
}
initData() {
this.dataObs$ = this.load();
this.dataObs$.subscribe((res: Data[]) => {
this.data = res;
this.completed = true;
});
}
}
add.component.ts
import { Component, OnDestroy, OnInit } from '@angular/core';
import { DataService } from '../../shared/data/data.service';
@Component({
selector: 'add',
templateUrl: './add.component.html',
styleUrls: ['./add.component.scss']
})
export class AddComponent implements OnInit, OnDestroy {
radioUrl: string;
constructor(private service: DataService) {
console.log('Add component built');
}
ngOnInit() {
this.service.initData();
console.log('Add component initialized');
}
ngOnDestroy() {
console.log('Add component destroyed');
}
}
type1.component.ts
import { Component, OnDestroy, OnInit } from '@angular/core';
@Component({
selector: 'type1',
templateUrl: './type1.component.html',
styleUrls: ['./type1.component.scss']
})
export class Type1Component implements OnInit, OnDestroy {
title = 'Add Block Stuff';
constructor() {
console.log('Type1 component built');
}
ngOnInit() {
console.log('Type1 component initialized');
}
ngOnDestroy() {
console.log('Type1 component destroyed');
}
onType1Change($event: any) {
console.log($event);
}
}
block.component.ts
import { Component, OnDestroy, OnInit, Output, EventEmitter, Input } from '@angular/core';
import { Logger } from 'ngx-data-utils';
import { Observable } from 'rxjs/Observable';
import { Data } from 'si-data-model';
import { DataService } from '../../shared/data/data.service';
@Component({
selector: 'block',
templateUrl: './block.component.html',
styleUrls: ['./block.component.scss']
})
export class BlockComponent implements OnInit, OnDestroy {
dataLoaded = false;
labels = ['Label1', 'Label2', 'Label3', 'Label4', 'Label5'];
selected: any[] = [];
data1: string;
data2: string;
data3: string;
data4: string;
data5: string;
data6: string;
datas: Data[] = [];
@Output() change: EventEmitter<any> = new EventEmitter();
@Input() title: string;
@Input() data: Data[];
// private criteriaCodes = [6, 2, 3, 11, 29, 25];
constructor(private logger: Logger,
private dataService: DataService) {
// TODO
}
ngOnInit() {
this.display();
this.logger.debug('BlockComponent initialized.');
}
ngOnDestroy() {
this.logger.debug('BlockComponent destroyed.');
}
initData () {
this.dataService.data.forEach((dt: Data) => {
this.datas.push(dt);
this.dataLoaded = true;
});
}
display() {
if (this.dataService.completed)
this.initData();
}
propagateChange() {
this.change.emit(this.selected); // doesn't do anything yet
}
}
block.component.html
<div class="row" *ngIf="dataLoaded">
<div class="row">
<div class="col-md-4">
<label>{{'DATA.BLOCK.LABEL1' | translate}}</label>
<select class="custom-select form-control" [(ngModel)]="data1" (change)="propagateChange()">
<option *ngFor="let c of data[0].value">{{c.code}} - {{c.description}}</option>
</select>
</div>
<div class="col-md-4">
<label>{{'DATA.BLOCK.LABEL2' | translate}}</label>
<select class="custom-select form-control" [(ngModel)]="data2" (change)="propagateChange()">
<option *ngFor="let mt of data[1].value">{{mt.code}} - {{mt.description}}</option>
</select>
</div>
<div class="col-md-4">
<label>{{'DATA.BLOCK.LABEL3' | translate}}</label>
<select class="custom-select form-control" [(ngModel)]="data3" (change)="propagateChange()">
<option *ngFor="let pem of data[2].value">{{pem.code}} - {{pem.description}}</option>
</select>
</div>
</div>
<div class="row">
<div class="col-md-4">
<label>{{'DATA.BLOCK.LABEL4' | translate}}</label>
<select class="custom-select form-control" [(ngModel)]="data4" (change)="propagateChange()">
<option *ngFor="let tt of data[3].value">{{tt.code}} - {{tt.description}}</option>
</select>
</div>
<div class="col-md-4">
<label>{{'DATA.BLOCK.LABEL5' | translate}}</label>
<select class="custom-select form-control" [(ngModel)]="data5" (change)="propagateChange()">
<option *ngFor="let cl of data[4].value">{{cl.code}} - {{cl.description}}</option>
</select>
</div>
<div class="col-md-4">
<label>{{'DATA.BLOCK.LABEL6' | translate}}</label>
<input type="text">
</div>
</div>
</div>