I have an Angular Reactive Form with Angular Materials
For all my controls I add the required validator.
I'm not sure how to setup the chips control correctly with reactive forms.
Where do you set the formControlName so that the required validator fires? At the moment I have it set on the input field which I'm guessing is wrong.
I just want the courseIds to be a comma seperated string with the course ids.
TS:
form: FormGroup;
ngOnInit() {
this.form = new FormGroup({
name: new FormControl("", [Validators.required]),
courseIds: new FormControl("", Validators.required)
});
}
HTML:
<form [formGroup]="form" (ngSubmit)="submit()">
<mat-form-field>
<input matInput type="text" formControlName="name" placeholder="Name">
</mat-form-field>
<mat-form-field>
<mat-chip-list #chipList>
<mat-chip *ngFor="let cid of courseIds" (removed) = "...">
{{cid}}
</mat-chip>
<input matInput formControlName="courseIds"
[matChipInputFor]="chipList"
placeholder="Ids"
(matChipInputTokenEnd)="add($event)">
</mat-chip-list>
</mat-form-field>
....
<button type="submit">OK</button>
</form>
Binding FormArray to Template We use the formArrayName directive to bind the skills form array to the div element. Now the div and anything inside the div element is bound to the skills form array. Inside the div use ngFor to loop through each element of skills FormArray.
Try setting the formControlName
at the <mat-chip-list>
level.
In your template, set the ngFor
to loop over the courseIds
control value
<mat-form-field>
<mat-chip-list #chipList formControlName="courseIds">
<mat-chip *ngFor="let cid of form.get('courseIds').value" (removed) = "...">
{{cid}}
</mat-chip>
<input matInput
[matChipInputFor]="chipList"
placeholder="Ids"
(matChipInputTokenEnd)="add($event)">
</mat-chip-list>
</mat-form-field>
Then in your component, create the form group with the initial values for courseIds
if any, else use an empty array []
(since the chips display an array and not a string). In your add()
and remove()
function, add and remove the values from the courseIds
control value respectively.
form: FormGroup;
ngOnInit() {
this.form = new FormGroup({
name: new FormControl("", [Validators.required]),
courseIds: new FormControl([], Validators.required)
});
}
add() {
...
// Add new input to courseIds control value
this.courseIds.value.push(value);
this.courseIds.updateValueAndValidity();
}
remove() {
...
// Remove element from control value array
this.courseIds.value.splice(index, 1); // where index = index of removed element
this.courseIds.updateValueAndValidity();
}
// use getter method to access courseIds control value easily
get courseIds() {
return this.form.get('courseIds');
}
When combining FormArrays with nash11 his answer it won't work. I had the problem that when i edit another formArray in the same form group the changes in the mat-chip list where lost.
Therefore here is my solution how to use material chip control with reactive forms + forms array.
https://stackblitz.com/edit/angular-9gjwo4-h4f9ux?file=app/chips-input-example.ts
chips-input-example.html:
<form [formGroup]="form">
<mat-form-field class="example-chip-list">
<mat-chip-list #chipList aria-label="Fruit selection" formArrayName="fruits">
<mat-chip *ngFor="let fruit of fruitControls.value" [selectable]="selectable" [removable]="removable"
(removed)="remove(fruit)">
{{fruit}}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
<input placeholder="New fruit..."
[matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="add($event)">
</mat-chip-list>
</mat-form-field>
</form>
chips-input-example.ts
import { COMMA, ENTER } from "@angular/cdk/keycodes";
import { Component } from "@angular/core";
import { MatChipInputEvent } from "@angular/material/chips";
import {
FormControl,
FormGroup,
FormGroupDirective,
NgForm,
Validators,
FormBuilder,
FormArray
} from "@angular/forms";
/**
* @title Chips with input
*/
@Component({
selector: "chips-input-example",
templateUrl: "chips-input-example.html",
styleUrls: ["chips-input-example.css"]
})
export class ChipsInputExample {
visible = true;
selectable = true;
removable = true;
addOnBlur = true;
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
fruits: this.fb.array(["Lemon", "Lime", "Apple"], Validators.required)
});
}
get fruitControls(): FormArray {
return this.form.controls.fruits as FormArray;
}
add(event: MatChipInputEvent): void {
const input = event.input;
const value = event.value;
// Add our fruit
if ((value || "").trim()) {
this.fruitControls.push(this.fb.control(value));
}
// Reset the input value
if (input) {
input.value = "";
}
}
remove(fruit: string): void {
const index = this.fruitControls.value.indexOf(fruit);
if (index >= 0) {
this.fruitControls.removeAt(index);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With