Reputation: 61
I have an application where I'm using the angular cdk stepper and I'm trying to share data between a common grandchild component in both of the child step components.
The first child passes the data to populate the grandchild, but the problem seems to be that the stepper initializes both components at the same time, and since the first child has to make a service call to populate the grandchild, the second child's child is initialized with incomplete data.
parent.component.html:
<app-custom-stepper>
<cdk-step [stepControl]="frmStep1" #step1="cdkStep">
<ng-template cdkStepLabel>Step1</ng-template>
<form #frmStep1="ngForm">
<child1 [myData]="myData"></child1>
</form>
<button cdkStepperPrevious>Prev</button>
<button cdkStepperNext>Next</button>
</cdk-step>
<cdk-step cdkStep #step2="cdkStep">
<form #frmStep2="ngForm">
<child2></child>
</form>
<button cdkStepperPrevious>Prev</button>
<button cdkStepperNext>Next</button>
</cdk-step>
parent.service.ts
export class ParentService {
myData:Subject<any> = new Subject<any>();
setMyData(data: any) {
this.myData.next(data);
}
getMyData(): Observable<any> {
return this.myData.asObservable();
}
}
child1.component.html:
<sharedGrandchild [myData]="myData"></sharedGrandchild>
child2.component.html
<sharedGrandchild></sharedGrandchild>
grandchild.component.ts:
@Input() myData:MyData;
ngOnInit() {
if(this.myData) {
//call service that populates data, this only happens on the page
//step of the stepper
this.parentService.setMyData(response);
} else {
this.parentService.getMyData()
.subscribe( myData => {
this.myData = myData
}
};
Things I've tried:
Using BehaviorSubjects and Subjects (like in the above code) Using a switch to delay initialization of the second child component Trying to use other lifecycle hooks to initialize the subscribe for the second childs component.
The issue is timing, that request the first child fires via the grandchild takes too long to return, so the grandchild present in the second child is subscribing to an object that is only partially present. This never seems to get updated. So the first child on the page loads fine since it's hitting the service directly, the second child on the second page of the stepper has incomplete data due to being initialized at the same time.
Upvotes: 0
Views: 188
Reputation: 11243
You should follow these steps to ensure the data is being shared asynchronously-
1.Use BehaviorSubject
to store the last set values.
myData:Subject<any> = new BehaviorSubject<any>(null);
2.Read and set the data in function ngAfterViewInit
instead of ngOnInit
@Input() myData:MyData;
ngAfterViewInit() {
if(this.myData) {
//call service that populates data, this only happens on the page
//step of the stepper
this.parentService.setMyData(response);
} else {
this.parentService.getMyData()
.subscribe( myData => {
this.myData = myData
}
};
3.Ensure that ParentService
is provided in the common module or Main Module or root module.
Upvotes: 1