Reputation: 3859
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++;
});
}
}
Upvotes: 0
Views: 6989
Reputation: 57981
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, e.g.
{
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 (e.g. [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 e.g.
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
Upvotes: 2