Tuesday, 19 March 2019

Angular Reactive Form Array, Change detection overriding form

Ive used the following question as a basis for my form design for a FormArray. The jist of what im trying to do is keep a form up to date with changes elsewhere on the page, but toggle a boolean/checkbox in this form. (Users have a list of cards they select, this form shows a list of this selection)

Unfortunately, uit seems that ngOnchanges is constantly updating the form, and my changes are being overwritten. In my constructor I detect value changes, with an intent to emit those changes. However,

this.contextSummaryForm.dirty

is always false. A breakpoint on rebuildForm() demonstrates that the method is invoked multiple times a second - thus changing contextItem.isEditEnable to false is completely overwritten. I can read my logic and see why that is happening sort of - but I seriously don't understand what I'm supposed to do to allow updates to contextList from its parent component AND allow users to update the form here.

Constructor, and change detection

@Input()
contextList: ContextItem[];

@Output()
contextListChange  = new EventEmitter<any>();

valueChangeSubscription = new Subscription;
contextSummaryForm: FormGroup;
isLoaded: boolean = false;


constructor(protected fb: FormBuilder) {
   this.createForm();


   this.valueChangeSubscription.add(
         this.contextSummaryForm.valueChanges
         .debounceTime(environment.debounceTime)
           .subscribe((values) => {
           if (this.isLoaded && this.contextSummaryForm.valid && this.contextSummaryForm.dirty) {

             this.contextSummaryForm.value.plans.forEach(x => {
               var item = this.contextList.find(y => y.plan.id === x.id);
               item.isEditEnabled = x.isEditEnabled;
             });

             this.contextListChange.emit(this.contextList);
             this.contextSummaryForm.markAsPristine();
           }
         }));
     }

Form Creation:

createForm(): void {
 this.contextSummaryForm = this.fb.group({
  plans: this.fb.array([this.initArrayRows()])
 });
}

initArrayRows(): FormGroup {
  return this.fb.group({
   id: [''],
   name: [''],
   isEditEnabled: [''],
});
}

OnChanges

  ngOnChanges(changes: SimpleChanges) {
for (let propName in changes) {
  if (propName === 'contextList') {
    if (this.contextList) {
      this.rebuildForm();
      this.isLoaded = true;
    }
  }
}
}

rebuildForm() {
  this.contextSummaryForm.reset({
  });
  //this.fillInPlans();
  this.setPlans(this.contextList);
}


  setPlans(items: ContextItem[]) {
    let control = this.fb.array([]);
    items.forEach(x => {
      control.push(this.fb.group({
        id: x.plan.id,
        name: x.plan.Name,
        isEditEnabled: x.isEditEnabled,
      }));
    });
    this.contextSummaryForm.setControl('plans', control);
  }

Just to summarize: i need a way to use formarrays built from an input binding that keeps up with changes without rapidly overwriting the form.



from Angular Reactive Form Array, Change detection overriding form

No comments:

Post a Comment