Using a getter results in multiple calls throughout the lifecycle of the component.
A different approach is necessary. One option is to subscribe to the valueChanges of the form and update the "states" within the subscription, like so:
export class StateComponent {
_studentForm;
@Input()
set studentForm(value)
{
this._studentForm=value;
this._studentForm.get(this.countryId).valueChanges.subscribe(res=>{
var val = this._studentForm.controls[this.countryId].value;
this.states=this.selectService.filterStates(val);
})
}
@Input() id:string;
@Input() countryId:string;
states: State[];
constructor(private selectService: SelectService) { }
}
Your component's HTML should reference _studentForm
<form [formGroup]="_studentForm">
<select [formControlName]="id" >
<option [value]="0">--Select--</option>
<option *ngFor="let state of states " value= {{state.id}}>{{state.name}}</option>
</select>
</form>
Check out your modified stackblitz here
Update
Considering the complexity of the issue, it might be time to create a component that controls both country and states simultaneously. This will involve using viewProviders and FormGroupDirective.
The new component would look something like this:
@Component({
selector: 'app-country-state',
viewProviders: [
{
provide: ControlContainer,
useExisting: FormGroupDirective
}
],
templateUrl: './country-state.component.html',
styleUrls: ['./country-state.component.css']
})
export class CountryStateComponent implements OnInit, OnDestroy {
@Input() countryID: string;
@Input() stateID: string;
@Input() countryLabel: string;
@Input() stateLabel: string;
_countryID: FormControl;
_stateID: FormControl;
states: any[] = [];
countries: any[] = [];
isAlive: boolean = true;
constructor(private selectService: SelectService,
private fgd: FormGroupDirective) { }
ngOnInit() {
this.countries = this.selectService.getCountries();
this._countryID = (this.fgd.form.get(this.countryID) as FormControl);
this._stateID = (this.fgd.form.get(this.stateID) as FormControl);
this._countryID.valueChanges.pipe(
takeWhile(() => this.isAlive)
).subscribe(res => {
this.states = this.selectService.filterStates(this._countryID.value);
})
}
ngOnDestroy() {
this.isAlive = false;
}
}
The corresponding .html file:
{{countryLabel}}:<br/>
<select [formControl]="_countryID">
<option [value]="0">--Select--</option>
<option *ngFor="let country of countries" [value]="country.id">{{country.name}}</option>
</select>
<br/>
{{stateLabel}}:<br/>
<select [formControl]="_stateID" >
<option [value]="0">--Select--</option>
<option *ngFor="let state of states " value= {{state.id}}>{{state.name}}</option>
</select>
Usage example:
<app-country-state
[countryID]="'countryId1'" [countryLabel]="'Student Country'"
[stateID]="'stateId1'" [stateLabel]="'Student State'">
</app-country-state>
Experience the changes in the updated stackblitz