1

I am trying to send a form to a backend which awaits the following JSON structure:

{
    name: "stringName",
    allowedFields: []
}

I have a model object for this

export class MyClass {
  @required()
  name: string;

  @propArray(String)
  allowedFields: Array<String>;
}

In the documentation they alway speak of custom objects but not the basic types like string Arrays: https://www.npmjs.com/package/@rxweb/reactive-form-validators/v/1.2.2?activeTab=readme#more-information-about-validators-and-validation-decorators

In the html I am trying to use Bootstrap Switches to display a set of possible values which should be sent to the backend like this:

<div [formGroup]="field" *ngFor="let field of myFormGroup.controls.allowedFields.controls">
    <div class="custom-control custom-switch">
      <input type="checkbox" class="custom-control-input"
             [value]="field.memberName">
      <label class="custom-control-label">{{field.memberName}}</label>
    </div>
</div>

Has anybody an idea on how to achieve to send an array of strings to the backend? Cheers Maik

1 Answer 1

2

NOTE: This first part is NOT for your problem. In general, when you need a form must be like

form=new FormGroup({
  name:new FormControl(),
  allowedFields:new FormArray([]);
})

So make three function and a getter and declare a variable form:

form:FormGroup;

get allowedFields()
{
    return this.form.get('allowedFields') as FormArray;
}

getForm(data:any)
{
   data=data||{data:null,allowedFields:[]}
   return new FormGroup({
      name:new FormControl(data.name),
      allowedFields:new FormArray(data.allowedFields.map(x=>new FormControl(x)))
    }) 
}
addAllowedField(data:string)
{
    this.allowedFields.push(new FormControl(data));
}
removeAlloedField(index)
{
    this.allowedFields.removeAt(index)
}

Your .html

<form [formGroup]="form" (submit)="submit(form)">
  <input formControlName="name">
  <div formArrayName="allowedFields">
    <button type="button" (click)="addAllowedField(null)">add</button>
  <div *ngFor="let control of allowedFields.controls;let i=index" >
    <input [formControlName]="i">
    <button type="button" (click)="removeAllowedField(i)">remove</button>
  </div>
  </div>
  <button type="submit">submit</button>
</form>

See that you write <div formArrayName="allowedFields"> and iterate over allowedFields.controls -is the "getter" defined in .ts. To control the "input" you can use [formControlName]="i" (or [formControl]="control" -control is the variable of the *ngFor

THIS PART is your about your QUESTION

But you want a series of checkbox and send and array with the values selected, so your form it's only two field

form=new FormGroup({
      name:new FormControl(),
      allowedFields:new FormControl();
})

See that "allowedFields" is a FormControl, NOT a FormArray.

A suppose you has an array of "allowedFields", make it an array of object, e.g.

fieldList=[
   {id:1,name:"field one"},
   {id:2,name:"field two"},
   {id:3,name:"field three"},
]

We are going to use inputs that not belong to the formGroup, yes [(ngModel)] in a ReactiveForms

<form [formGroup]="form" (submit)="submit(form)">
  <input formControlName="name">
  <div *ngFor="let item of fieldList;let i=index" >
    <input type="checkbox"
        [ngModel]="item.check" 
        (ngModelChange)="item.check=$event;setAllowedFields()"
         [ngModelOptions]="{standalone:true}"
    >{{item.name}}
  </div>
  <button type="submit">submit</button>
</form>

And a function

setAllowedFields()
{
   this.form.get('allowedFields').setValue(this.fieldList
           .filter(x=>x.checked)
           .map(x=>x.id))
}

See stackblitz

Update for prepopulate the checks, as always, we has a function to return the formGroup

getGroup(data)
{
   data=data || {name:'',allowedFields:[]}

   //prepopulate the data
   this.fieldList.forEach(x=>{
       x.check=data.indexOf(x.id>=0)
   })
   /* //or 
   allowedField.forEach(x=>{
     const field=this.fieldList.find(f=>f.id==x)
     if (field)
         field.check=true;
   })
   */
   return new FormGroup({
          name:new FormControl(data.name),
          allowedFields:new FormControl(data.allowedFields);
    })

}  

You use as

   this.form=this.getGroup(null) //<--a empty form
   this.form=this.getGroup(data) //<-- a form with data
Sign up to request clarification or add additional context in comments.

5 Comments

That's a valid solution, but this one is even shorter: github.com/rxweb/rxweb/issues/304
@Barzille, I like more my approach. You are using a helper variable "projectDomains" instead of a "computed" value. Use a computed value make that we needn't take care about discordance between the values, but of course your aproach is perfect valid
have you tried to prepopulate your checkboxes with values from the "server"? For me it seems it is not updating the checkboxes to the checked state.
I updated the answer to prepopulated the checkBox. I like has a function to create the formGroup that you call using as argument null or an object
Bit off Topic: I am using RxFormBuilder to populate a form having 100+ data items some are string,some boolean, some array and some objects.. this._formBuilder.formGroup(Data, data) works fine and return perfect rxFormGroup if items are not null. But in case item are not there then it return null is there anyway we can create defaults like empty array and empty objects ? I am not sure new to this hence asking. Please Help

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.