Abhishek
Abhishek

Reputation: 2034

Angular 7: Trigger valuechanges on addControl, if value's present

I'm adding/removing controls from my form based on some conditions.

if(true) {
  this.form.addControl('age', new FormControl(this.resp.age));
}
this.form.get('age').valueChanges.subscribe(val => {
   //Do something.
});

So what exactly is required here is when a control is added, I need to trigger the valuechanges asosciated with this control. I know that when this control is added and value is set, the valuechanges is not in scope till that time and comes into the picture later. So what can be done here to trigger it when control is added.

Upvotes: 2

Views: 1974

Answers (2)

user4676340
user4676340

Reputation:

valueChanges need to be triggered by ... Well, a value change. But you can use an operator to change that :

this.form.get('age').valueChanges
  .pipe(startWith(this.form.get('age').value))
  .subscribe(value => {...});

I actually make several RxJS operators for those kind of questions in my projects, here is this one :

export function firstValueOfControl<T>(control: AbstractControl) {
  return control.valueChanges.pipe(startWith(control.value));
}
...
firstValueOfControl(this.form.get('age')).subscribe(value => {...});

EDIT

Didn't see the if value's present part. Simply add a filter :

this.form.get('age').valueChanges
  .pipe(startWith(this.form.get('age').value), filter(v => !!v)
  .subscribe(value => {...});

For the operators :

export function filterTruthy<T>() {
  return filter<T>(v => !!v);
}

firstValueOfControl(this.form.get('age'))
  .pipe(filterTruthy())
  .subscribe(value => {...});

Upvotes: 3

Chanaka Weerasinghe
Chanaka Weerasinghe

Reputation: 5742

use ngFor inside your template and bind dynamic formControlName.

Template:

 <form [formGroup]="formGroup">
  ...
  <ul>
    <li *ngFor="let question of questions">
      <input [formControlName]="questions.id">
    </li>
  </ul>
  ...
</form>

Component:

const questions = [{id: 1}, {id: 2}]; // just for demo
this.formGroup = this.fb.group(
  questions.reduce((acc, curr) => ({ ...acc, [curr.id]: '' }), {})
);

This will generate formGroup based on this object: {1: "", 2: "", 3: ""}. If you want, you can also set initial values to the form controls:

const questions = [{id: 1, value: 'q1'}, {id: 2, value: 'q2'}]; // just for demo
this.formGroup = this.fb.group(
  questions.reduce((acc, curr) => ({ ...acc, [curr.id]: curr.value }), {})
);

Upvotes: 0

Related Questions