I have built a component in my Angular App that handles client information; this is my ClientDetailsComponent
, inside this component there are other subcomponents that each fetch their own data when a user enters the main ClientDetailsComponent
; this of course causes the main component to load a lot of stuff that users might not even need at the moment so I was trying to look for a way to lazy-load this sections.
Now my component has a sidebar that serves as a navigation menu to only display specific sections when clicked, right now I've built a very primitive navigation menu, relying on classes to hide/show each section.
ClientDetailsCompnent
<div class="wrapper">
<div class="sidebar-nav">
<nav>
<ul class="sections-list" btnRadioGroup [formControl]="navControl">
<li btnRadio="0" tabindex="0" role="button">Basic Information</li>
<li btnRadio="1" tabindex="0" role="button" *ngIf="!isNew">PPC Accounts</li>
<li btnRadio="2" tabindex="0" role="button" *ngIf="!isNew">Campaign Groups</li>
<li btnRadio="4" tabindex="0" role="button" *ngIf="!isNew">Optimizations</li>
<li btnRadio="5" tabindex="0" role="button" *ngIf="!isNew">Branding</li>
<li btnRadio="3" tabindex="0" role="button" *ngIf="!isNew">Sharing</li>
</ul>
</nav>
</div>
<div class="content">
<div class="wsm-container">
<!-- Basic Information -->
<section id="basic-info" class="wsm-card mx-auto d-none" [ngClass]="navControl.value === '0' ? 'd-flex' : 'd-none'">
</section>
<!-- PPC Accounts -->
<section *ngIf="!isNew" id="ppc-accounts" class="wsm-card mt-4 d-none" [ngClass]="navControl.value === '1' ? 'd-flex' : 'd-none'">
</section>
<!-- Campaign Groups -->
<section *ngIf="!isNew && navControl.value === '2'" class="wsm-card mt-4 d-none" [ngClass]="navControl.value === '2' ? 'd-flex' : 'd-none'">
<app-campaign-groups [clientID]="param"></app-campaign-groups>
</section>
<!-- Optimizer History -->
<section *ngIf="!isNew && navControl.value === '4'" id="optHistory" class="wsm-card mt-4 d-none" [ngClass]="navControl.value === '4' ? 'd-flex' : 'd-none'">
<app-optimization-history></app-optimization-history>
</section>
<!-- Branding -->
<section id="brnading" class="wsm-card mx-auto d-none" [ngClass]="navControl.value === '5' ? 'd-flex' : 'd-none'">
</section>
</div>
</div>
</div>
Regarding the navigation, everything works pretty much as I'd expect, only one section displayed at a time, depending on which item I clicked on the sidebar; however, just doing that doesn't prevent all request to be made at once when I access the component.
So one workaround I found while trying various options, was using the navControl.value === ''
condition on the *ngIf
directive of the section, so instead of only changing classes with the [ngClass]
directive, I also prevent the section to be added to the DOM and in fact I see that the request for each subcomponent are only made once I click on the needed tab.
The issue now is that the requests are made eveytime I click on a different tab, since the component is added/removed everytime I move between sections.
Is there a way to keep the subcomponent loaded once I accessed it so it doesn't need to re-render it and fetch data again?
Create service with ReplaySubject:
@Injectable({
providedIn: "root"
})
export class DataService {
private _replay: ReplaySubject<any>;
get replay() {
if (!this._replay) {
this._replay = new ReplaySubject();
this.fakeFetch().then(data => this.replay.next(data));
}
return this._replay;
}
async fakeFetch() {
console.log("fakeFetch");
await new Promise(c => setTimeout(() => c(), 10));
return { name: "world" };
}
}
And in your component subscribe to replay subject :
export class HelloComponent {
name: string;
constructor(private api: DataService) {
console.log('render HelloComponent')
this.api.replay.subscribe(data => {
this.name = data.name;
});
}
}