5

I've this component that use ControlValueAccessor. The component has his own inner form and I cannot find where to set the initial value for form controls.

Can someone point me in the right direction?

import {
  Component, ChangeDetectorRef, forwardRef,
  NgModule, OnInit} from '@angular/core';
import { FormGroup, FormControl, FormBuilder } from '@angular/forms';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { debounceTime } from 'rxjs/operators';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

export const ADDRESS_VALUE_ACCESSOR: any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => AddressFormComponent),
  multi: true
};


@Component({
  selector: 'app-address-form',
  templateUrl: 'address-form.component.html',
  providers: [ADDRESS_VALUE_ACCESSOR],
})
export class AddressFormComponent implements OnInit, ControlValueAccessor {

  addressForm: FormGroup;

  private innerValue: any;

  onModelTouched: Function = () => { };
  onModelChange: Function = () => { };

  constructor(
    private _fb: FormBuilder,
    private ref: ChangeDetectorRef,

  ) {  }

  ngOnInit() {

    this.addressForm = this._fb.group({
      'via': new FormControl(''),
      'civico': new FormControl(''),
      'cap': new FormControl(''),
      'comune': new FormControl(''),
      'provincia': new FormControl(''),
      'regione': new FormControl(''),
      'stato': new FormControl(''),
      'frazione': new FormControl('')
    });

  }

  // get accessor
  get value(): any {
    return this.innerValue;
  }

  // set accessor including call the onchange callback
  set value(v: any) {
    if (v !== this.innerValue) {
      this.innerValue = v;
      this.onModelChange();
    }
  }

  // ngAfterViewInit(): void {
  //   if (this.value != null) {
  //     this.addressForm.get('via').setValue(this.value.via);
  //     this.addressForm.get('civico').setValue(this.value.civico);
  //     this.addressForm.get('cap').setValue(this.value.cap);
  //     this.addressForm.get('comune').setValue(this.value.comune);
  //     this.addressForm.get('provincia').setValue(this.value.provincia);
  //     this.addressForm.get('frazione').setValue(this.value.frazione);
  //     this.addressForm.get('stato').setValue(this.value.stato);
  //     this.addressForm.get('regione').setValue(this.value.regione);
  //   }
  // }


  // Set touched on blur
  onBlur() {
    this.onModelTouched();
  }

  writeValue(value: any): void {
    this.value = value;
    this.ref.markForCheck();
  }

  registerOnChange(fn: Function): void {

    this.addressForm.valueChanges.subscribe(() => {
      fn(this.addressForm.value);
    });

    this.onModelChange = fn;
  }

  registerOnTouched(fn: Function): void {
    this.onModelTouched = fn;
  }
}

@NgModule({
  imports: [

    CommonModule,
    FormsModule,
    ReactiveFormsModule

  ],
  exports: [AddressFormComponent],
  declarations: [
    AddressFormComponent
  ],
  entryComponents: [AddressFormComponent],
  providers: [

  ]
})

export class AddressFormModule { }

view:

<form [formGroup]="addressForm">

  <div class="row">
      <div class="form-group col-md-10">
          <label for="txtVia">Via</label>
          <input type="text" pInputText class="form-control" id="txtVia"
              formControlName="via">
      </div>
      <div class="form-group col-md-2">
          <label for="txtCivico">Civico</label>
          <input type="text" pInputText class="form-control" id="txtCivico"
              formControlName="civico">
      </div>
  </div>
  <div class="row">
      <div class="form-group col-md-3">
          <label for="txtCap">Cap</label>
          <input type="text" pInputText class="form-control" id="txtCap"
              formControlName="cap">
      </div>
      <div class="form-group col-md-6">
          <label for="txtComune">Comune</label>
          <input type="text" pInputText class="form-control" id="txtComune"
              formControlName="comune">
      </div>
      <div class="form-group col-md-3">
          <label for="txtProvincia">Provincia</label>
          <input type="text" pInputText class="form-control" id="txtProvincia"
              formControlName="provincia">
      </div>
  </div>
  <div class="form-group">
      <label for="txtFrazione">Frazione</label>
      <input type="text" pInputText class="form-control" id="txtFrazione"
          formControlName="frazione">
  </div>
  <div class="row">
      <div class="form-group col-md-6">
          <label for="txtRegione">Regione</label>
          <input type="text" pInputText class="form-control" id="txtRegione"
              formControlName="regione">
      </div>
      <div class="form-group col-md-6">
          <label for="txtStato">Stato</label>
          <input type="text" pInputText class="form-control" id="txtStato"
              formControlName="stato">
      </div>
  </div>

</form>

1 Answer 1

6

Inside the writeValue function set the values

 writeValue(value: any): void {
    this.value = value;
    if (this.value != null) {
      this.addressForm.get('via').setValue(this.value.via);
    }
    this.ref.markForCheck();
  }
Sign up to request clarification or add additional context in comments.

2 Comments

I assume the this.ref.markForCheck() is not required unless you have changeDetection: ChangeDetectionStrategy.OnPush
The problem I see here is the following: --- YOU NOW successfully initialised the form with a default value. (=> A value not being given from outside during initialisation of the control value accessor (cva) but coming from inside it) --- BUT YOU never told the parent component about this. From this moment until the default value is changed by the cva, the parent component using the cva inside a form will never know about this default value, so the form is invalid seen from outside even though it is valid from the inside.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.