简体   繁体   中英

Patch values to checkbox using patchValue in angular

I'm trying to re-use my create-form to edit the values of the form. My checkbox is working as per requirement while creating a form. When I click on edit form, the values aren't patching to my checkbox. Below is my code which I have tried:

<div class="form-row">
  <div class="form-group col-sm-6">
    <label>Authorized To</label>
    <br>
    <label *ngFor="let choice of authorized; let i=index">
      <input type="checkbox" [value]="choice" (change)="onCheckChange($event)" [checked]="checkedVal"
          formArrayName="authorized" type="checkbox[class.invalid]="! formGrowLicense.controls['authorized'].valid && formGrowLicense.controls['authorized'].touched ">
                            {{choice}}
     </label>
    <div *ngIf="!formGrowLicense.controls['authorized'].valid && (formGrowLicense.controls['authorized'].touched || isSubmitted)">
      <div class="invalid-feedback" style="display: block;">Please enter authorized to</div>
    </div>

  </div>
</div>

ts

authorized: any = ['CULTIVATE', 'HARVEST', 'PROCESS']; //displaying list of checkbox
constructor() {
  this.formGrowLicense = this.formBuilder.group({
      businessName: ['', Validators.required], 
      authorized: new FormArray([], [Validators.required])
       });
   } 
 getGrowLicense(id) {
    this.httpService.getGrowLicenseById(id).subscribe(
      response => {
        this.patchGrowLicense(response);
        this.checkedVal = response.authorisedTo; // tried storing response in this variable  ['CULTIVATE','HARVEST']
      },

      (err: any) => console.log(err)
    );
  }
patch(licenseObj){
    this.formGrowLicense.patchValue({
      businessName:licenseObj.companyName,
      authorized: licenseObj.authorisedTo, // here i'm getting response ['CULTIVATE','HARVEST']. Need to patch these two values as checked in checkbox
      });
    }

 onCheckChange(event) {
    this.formArray = this.formGrowLicense.get(
      'authorized'
    ) as FormArray;

    /* Selected */
    if (event.target.checked) {
      console.log(event.target.value);
      // Add a new control in the arrayForm
      this.formArray.push(new FormControl(event.target.value));
    } else {
      /* unselected */
      // find the unselected element
      let i = 0;

      this.formArray.controls.forEach((ctrl: FormControl) => {
        if (ctrl.value == event.target.value) {
          // Remove the unselected element from the arrayForm
          this.formArray.removeAt(i);
          return;
        }

        i++;
      });
    }
  }

You has an FormArray of FormControls that takes values true/false and received and array of strings among a fixed array, so first you need transform the array received in an array of true/false

First approach

First we are going to create a Form with a formArray. As always we can manage a form array we need to create a getter that return our formArray

  //our getter formArray
  get authorizedArray()
  {
    return this.formGrowLicense.get('authorized') as FormArray
  }

  ngOnInit()
  { //we create the formArray
    this.formGrowLicense=new FormGroup({
      businessName:new FormControl(),
      authorized:new FormArray(this.authorized.map(x=>new FormControl(false)))
    })
  }

See that the way to create the formArray is using new FormArray(..here and array of formControls..) . And the way to create the formArray of formControls is "mapping" each element of the array "this.autorized" to a FormControl.

To manage in a series of inputs we using this.html

<form [formGroup]="formGrowLicense">
    <input formControlName="businessName">
    <!--we use formArrayName in a div-->
    <div formArrayName="authorized">
        <!--we iterate over autorizedArray.controls
           remember our getter of the formArray? -->
        <div *ngFor="let control of authorizedArray.controls;let i=index">
            <!--we use [formControlName]=i -->
            <label><input type="checkbox"  [formControlName]="i">{{authorized[i]}}</label>
        </div>
    </div>
</form>

As always, we check if it's all ok using (only for check) in the.html

<pre>
  {{formGrowLicense?.value|json}}
</pre>

See how we iterate over the formArrayControls, and use the index, to show in the label authorized[i]

Well, We know yet how control a form array, so the next question: how we feed the formArray with the values?

Remember that we received some like, eg

{
  businessName:'my business name'
  authorized:['CULTIVATE', 'PROCESS']
}

when we received the value in data we can use some like

   this.formGroupLicense.patchValue(
    {
     businessName:data.businessName,
     authorized:this.authorized.map(x=>data.authorized.indexOf(x)>=0)
    }

See how transform the "data.authorize" and array with 0,1,2 or 3 elements in an array of 3 elements that takes values true or false

Well, the last work we need is, in submit, use the values of the formArray (eg [true,false,false] to get an array of strings

submit(form)
{
   if (form.valid)
   {
        const data={
           businessName:form.value.businessName
           authorize:form.value.authorized.map(
              (x,index)=>x?this.authorized[index]:null)
              .filter(x=>x)
        }
        console.log(data) //<--here we has the data we send to the service
   }
}

Yes, we map the [true,false,false] to ['CULTIVATE',null,null] and filter and only want elements that are not null ['CULTIVATE']

Well, use pathValue is ok but why we not create a function that return a formGroup with the data we want

createFormGroup(data:any=null)
{
    data=data||{businessName:null,authorize:[]}
    return new FormGroup({
      businessName:new FormControl(data.businessName),
      authorized:new FormArray(this.authorized
        .map(x=>new FormControl(data.authorized.indexOf(x)>=0)))
    })
}

So, when we received the data the only thing we need is use

  this.formGroupLicense=this.createFormGroup(data)

Second approach

We has a form like

    this.formGrowLicense=new FormGroup({
      businessName:new FormControl(),
      authorized:new FormControl()
    })

YES. authorized is a FormControl that store an array. If you see the material multi checked is this approach. For this you can check this SO with use a custom formControl. Let me explain (I don't want a customFormControl)

We has an auxiliary array with two properties "name" and "value" we want to get some like eg

authorizedAux: any = [{name:'CULTIVATE',value:true}, 
                      {name:'HARVEST',value:false},
                      {name:'PROCESS',value:true}]

So we add a function

  setAutorized(data: string[]) {
    this.authorizedAux = this.authorized.map(x => ({
      name: x,
      value: data.indexOf(x) >= 0
    }));
  }

And another function parse

  parse() {
    const result=this.authorized
      .map((x, index) => (this.authorizedAux[index].value ? x : null))
      .filter(x => x);
    return result.length>0?result:null
  }

then we can has an html that use ngModel, ngModelChange and ngModelOptions to change the value of the FormControl

<form [formGroup]="form">
    <input formControlName="businessName">
        <div *ngFor="let control of authorizedAux">
            <label>
        <input type="checkbox"  
            [ngModel]="control.value"
            (ngModelChange)="control.value=$event;form.get('authorized').setValue(parse())"
            [ngModelOptions]="{standalone:true}"
      >{{control.name}}</label>
        </div>
</form>

Remember that, when received the data we need call to the function setAutorized

See the two approaches in the stackblitz

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM