Rohit Goyani
Rohit Goyani

Reputation: 1256

Angular - Custom form component not reflect value immediate to parent form group value

Facing issue with value propogation from custom form component.

If write any in Jobtitle, it will reflect directly from current to top form group. Same thing does not work in the custom component which is auto-add-input. While writing in feeMode, then only reflect in the same formControl.

but, then now, if start to write in company name, then all value updated up to top form group

Have created stackblitz as below

https://stackblitz.com/edit/angular-auto-add-input?file=src/app/app.component.html

Please help me what i missed here.

reactive form group

professional = this.fb.group({
    application: this.fb.group({
      jobTitle: ['', [Validators.required]],
      feeModel: this.fb.array([this.fb.control('', [Validators.required])], [Validators.required]),
      companyName: ['', [Validators.required]],
    })
  });

custom component:

 @Component({
  selector: 'shared-auto-add-input',
  templateUrl: './auto-add-input.component.html',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => AutoAddInputComponent),
      multi: true
    }
  ]
})
export class AutoAddInputComponent implements OnInit, AfterViewInit {

  @Input() label: string;
  @Input() placeholder: string;
  @Input() max: number;
  @Input() formArrayName: string;
  @Input() errors: ErrorModel[];

  arrayControl: FormArray;
  form: FormGroup;

  constructor(
    @Optional() @Host() @SkipSelf()
    private controlContainer: ControlContainer,
    private fb: FormBuilder,
  ) { }

  ngOnInit() {
    if (!this.formArrayName) {
      throw new TypeError('\'formArrayName\' is required.');
    }
    this.form = this.fb.group({
      option: this.controlContainer.control.get(this.formArrayName)
    });
    this.arrayControl = this.form.get('option') as FormArray;
  }

  ngAfterViewInit() {
  }

  addOption() {
    this.arrayControl.push(this.fb.control('', this.controlContainer.control.get(this.formArrayName).validator));
  }

  removeOption(index: number) {
    this.arrayControl.removeAt(index);
  }

  stopNew(option, i) {
    return option.value === ''
      || i !== this.arrayControl.controls.length - 1
      || (this.max && this.arrayControl.controls.length === +this.max);
  }

  getErrors(error: FormControl) {
    let result = [];
    if (this.errors) {
      result = this.errors.filter((message) => {
        return error.hasError(message.key);
      });
    }
    return result;
  }
}

Upvotes: 1

Views: 3900

Answers (3)

Rohit Goyani
Rohit Goyani

Reputation: 1256

Sorry, I missed to call updateValueAndValidity() after value change in the custom form component

this.form.valueChanges
      .subscribe(() => {
        this.controlContainer.control.updateValueAndValidity();
      });

Now, it is working.

Solved : https://stackblitz.com/edit/solved-angular-auto-add-input?file=src/app/auto-input/auto-add-input.component.ts

Upvotes: 2

Rajesh Panda
Rajesh Panda

Reputation: 646

The value is changed but there is no event triggered to re-render the values of the absolute parent object. In the child component you are operating under a new form with only the reference of the original formControl or formarray.

this.fb({}) creates a new form. The control values are changed as the reference is same but then it fails to render the new value as there is no trigger from the parent form which the parent page has been tracking.

That's why it is always a formgroup that is passed to child so that you do not create a new formgroup in there. Doing that, the formgroup is tracked just fine. Here is a quick modification of your code. I have used formcontrol as it is easier but then you can use the same trick with formArrays.

https://stackblitz.com/edit/angular-xchddm

Upvotes: 1

Geverson Carvalho
Geverson Carvalho

Reputation: 36

Looks like you are struggling with data bindings on your HTML file as you are binding a full object to print on HTML using a json filter. It seems not to be considering as changed when re-drawing the html as it has to compare an array inside an object. I don't think it is a problem (depending on what you want to do).

It turns out angular does a change check and depending on how you are binding on HTML, in your case a full object, it is not checking deeply if it has changed.

Upvotes: 0

Related Questions