Reputation: 639
I have a parent component with some childs that get rendered based on ngIf evaluation.
I'm on Angular 8.1.3
The parent component
import { ActivatedRoute } from '@angular/router';
import {FirstStageViewComponent} from "src/app/first-stage-view/first-stage-view.component";
import {SecondStageViewComponent} from "src/app/second-stage-view/second-stage-view.component";
import {SecondStageFormComponent} from "src/app/second-stage-form/second-stage-form.component";
import {ThirdStageFormComponent} from "src/app/third-stage-form/third-stage-form.component";
import {ThirdStageViewComponent} from "src/app/third-stage-view/third-stage-view.component";
import { ProdService } from "src/app/service/prod-service";
@Component({
selector: 'app-prod-view',
templateUrl: './prod-view.component.html',
styleUrls: ['./prod-view.component.css']
})
export class ProdViewComponent implements OnInit
{
id;
_stage: string;
constructor(private prodService: ProdService, private route: ActivatedRoute) { }
ngOnInit() {
this.route.params.subscribe(params => this.id=params.id);
this.prodService.get(this.id).subscribe((data: string) => (this._stage = data["_stage"]),
error => (console.log(error)));
}
talkBack(_updatedStage: string) {
this._stage=_updatedStage;
}
}
and its template
<div class="container">
<div *ngIf="_stage>0">
<app-first-stage-view [id]=id></app-first-stage-view>
</div>
<div *ngIf="_stage==1 else stage2">
<app-second-stage-form [id]=id (talk)=talkBack($event)></app-second-stage-form>
</div>
<ng-template #stage2>
<div *ngIf="_stage>1">
<app-second-stage-view [id]=id></app-second-stage-view>
</div>
</ng-template>
<div *ngIf="_stage==2 else stage3">
<app-third-stage-form [id]=id (talk)=talkBack($event)></app-third-stage-form>
</div>
<ng-template #stage3>
<div *ngIf="_stage>2">
<app-third-stage-view [id]=id></app-third-stage-view>
</div>
</ng-template>
</div>
This is the second child component (the one that doesn't get correctly initialized)
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { FormGroup, FormBuilder, FormArray, Validators } from "@angular/forms";
import { ThirdStageService } from "src/app/service/third-stage.service";
@Component( {
selector: 'app-third-stage-form',
templateUrl: './third-stage-form.component.html',
styleUrls: ['./third-stage-form.component.css']
} )
export class ThirdStageFormComponent implements OnInit {
tsForm: FormGroup;
@Input() id: string;
@Output() talk: EventEmitter<string> = new EventEmitter<string>();
constructor( private tsService: ThirdStageService,
private formBuilder: FormBuilder ) {}
ngOnInit() {
this.tsForm = this.formBuilder.group( {
ingredient: "TEST"
} );
}
}
And a shrunk template for testing
<div class="container">
<form [formGroup]="tsForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="name">{{ tsForm.controls[0].value }}</label> <input type="text"
class="form-control" id="ingredient" formControlName="ingredient"
required>
</div>
</form>
</div>
The parent retrieve the _stage value from server, and the first child gets correctly displayed.
Then this component talkback the new _stage value to its parent by an EventEmitter, and the parent update the value of its variable accordingly.
The new value (2) is the one that actually turns my second ngIf to true, and indeed second child (it's called third-stage-form, don't get confused) constructor gets called. But its ngOnInit doesn't fire up.
The default value "TEST" doesn't get shown inside my input field, and inspecting component tree through Augury, I can see that the two dependencies injected by constructor are present, while the formgroup created inside ngOnInit, is not.
If I create a new route pointing directly to my child component, everything works as expected.
Upvotes: 1
Views: 4167
Reputation: 525
You're using observables, which are asynchronous. Whatever's inside subscribe()
gets called when the request completes, which can happen at any time.
So, your this.id
is being set after you've already called subscribe on the second observable. You need to use some map that ensures order of the subscribes, like concatMap()
ngOnInit() {
this.route.params.pipe(
concatMap(params => this.prodService.get(params.id))
)
}
Upvotes: 1
Reputation: 57929
Javier, when you write
this.route.params.subscribe(params => this.id=params.id);
//here this.id has no value
this.prodService.get(this.id).subscribe(...)
You need use swithMap
this.route.params.pipe(
switchMap((params)=>{
//here you has "params"
this.id=params.id
//we want return
return this.prodService.get(this.id)
})
).subscribe((data: string) => (this._stage = data["_stage"]),
error => (console.log(error))
);
Upvotes: 0