How to implement a material chiplist in Angular 8 using formGroup

Struggling to include a chip list of Angular material within an Ng form? Unable to add a new chip list upon button click and uncertain about displaying the value of the array added in the new chip list. Take a look at this example: https://stackblitz.com/edit/angular-4d5vfj-g1ggqr

   <button (click)="addNewChip()">Add new Chip</button><br><br>

  <form [formGroup]="myForm">
  <mat-form-field class="example-chip-list">
  <mat-chip-list #chipList formArrayName="names">
  <mat-chip 
    *ngFor="let name of myForm.get('names').controls; let i=index;"
    [selectable]="selectable"
    [removable]="removable"
    (removed)="remove(myForm, i)">
    {{name.value}}
    <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
  </mat-chip>
  <input placeholder="Names"
    [matChipInputFor]="chipList"
    [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
    [matChipInputAddOnBlur]="addOnBlur"
    (matChipInputTokenEnd)="add($event, myForm)">
</mat-chip-list>
<mat-error>Atleast 1 name need to be added</mat-error>
</mat-form-field>
 </form>

component.ts file

export class ChipListValidationExample implements OnInit {
@ViewChild('chipList') chipList: MatChipList;
public myForm: FormGroup;

  // name chips
    visible = true;
  selectable = true;
  removable = true;
  addOnBlur = true;
   readonly separatorKeysCodes: number[] = [ENTER, COMMA];

// data
 data = {
  names: ['name1', 'name2']
  }

constructor(private fb: FormBuilder) {
this.myForm = this.fb.group({
  names: this.fb.array(this.data.names, this.validateArrayNotEmpty)
});
  }

ngOnInit() {
this.myForm.get('names').statusChanges.subscribe(
  status => this.chipList.errorState = status === 'INVALID'
);
}

 initName(name: string): FormControl {
return this.fb.control(name);
}

 validateArrayNotEmpty(c: FormControl) {
if (c.value && c.value.length === 0) {
  return {
    validateArrayNotEmpty: { valid: false }
  };
}
return null;
 }

  add(event: MatChipInputEvent, form: FormGroup): void {
const input = event.input;
const value = event.value;

// Add name
         if ((value || '').trim()) {
  const control = <FormArray>form.get('names');
  control.push(this.initName(value.trim()));
  console.log(control);
}

// Reset the input value
if (input) {
  input.value = '';
}
  }

   remove(form, index) {
console.log(form);
form.get('names').removeAt(index);
 }

  addNewChip(){
  console.log("Yse")
   this.myForm = this.fb.group({
  names: this.fb.array(this.data.names, this.validateArrayNotEmpty)
   });
   }

}

Answer №1

Is this the solution you were searching for?

  • I made adjustments to the addChip and removeChip methods so they now operate on the current Chiplist in the FormArray by passing the formControl to the methods.
  • I updated the data structure to accommodate a name and initial set of values.
  • The addNewChipList method was modified to include a formControl to the existing FormArray.
<button (click)="addNewChipList()">Add new Chip</button><br><br>

<form [formGroup]="myForm">
<ng-container formArrayName="names"
  *ngFor="let item of myForm.get('names').controls; let i = index;">
  <mat-form-field class="example-chip-list" [formGroupName]="i">
    <mat-chip-list #chipList >
      <mat-chip *ngFor="let val of item.value.val"
        [selectable]="selectable"
        [removable]="removable"
        (removed)="removeChip(item, val)">
        {{val}}
        <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
      </mat-chip>
      <input [placeholder]="item.value.name"
        [matChipInputFor]="chipList"
        [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
        [matChipInputAddOnBlur]="addOnBlur"
        (matChipInputTokenEnd)="addChip($event, item)">
    </mat-chip-list>
    <mat-error>Atleast 1 name need to be added</mat-error>
  </mat-form-field>
</ng-container>
</form>
// data
data = {
  names: [this.initName('name1'), this.initName('name2', ['A', 'B'])]
}

constructor(private fb: FormBuilder) {
  this.myForm = this.fb.group({
    names: this.fb.array(this.data.names, this.validateArrayNotEmpty)
  });
}

ngOnInit() {
  this.myForm.get('names').statusChanges.subscribe(
    status => this.chipList.errorState = status === 'INVALID'
  );
}

initName(name: string, val: string[]=[]): FormControl {
  return this.fb.control({ name, val });
}

validateArrayNotEmpty(c: FormControl) {
  if (c.value && c.value.length === 0) {
    return {
      validateArrayNotEmpty: { valid: false }
    };
  }
  return null;
}

addChip(event: MatChipInputEvent, ctrl: FormControl): void {
  const input = event.input;
  const value = event.value;

  // Add name
  if ((value || '').trim()) {
    const control = ctrl;
    control.value.val.push(value.trim());
    console.log(control.value);
  }

  // Reset the input value
  if (input) {
    input.value = '';
  }
}

removeChip(ctrl, val) {
  const idx = ctrl.value.val.findIndex(item => item === val);
  ctrl.value.val.splice(idx, 1);
}

addNewChipList() {
  const items = this.myForm.get('names') as FormArray;
  items.push(this.initName(`name${items.length + 1}`));
}

Check out the updated Stackblitz here.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Printing from a lengthy React DOM using window.print only generates a single page

My React component is capable of rendering markdown and can span multiple pages. Everything looks great when the component is displayed in the browser - scrolling works perfectly. However, whenever I try to print the page using window.print or ctrl + P, ...

Best practice for integrating Typescript into an established ASP.NET 4 Webforms project

Currently, I am working on an older asp.net 4.0 Webforms project using Visual Studio 2015. My goal is to transition from using Javascript to TypeScript for certain client side code tasks. While I have experience using TypeScript in projects outside of Vis ...

Extend the row of the table according to the drop-down menu choice

I am working on a feature where a dropdown menu controls the expansion of rows in a table. Depending on the option selected from the dropdown, different levels of items need to be displayed in the table. For example, selecting level 1 will expand the first ...

What is a sleek method for including a key and value pair to an object using an array?

In a project using angular2/typescript, I am working with an array of objects that contain key/value pairs from a database. These values are then displayed in a table on the UI using ag-grid-ng2. The table headers are dynamic and set in the database. One ...

Angular validation for password and confirmation password fields

I have been working on implementing password and confirm password validation within an angular project. I recently came across a helpful answer on this thread Confirm password validation in Angular 6 that I tried to follow. Unfortunately, I am encountering ...

The 'path' property is not found on the 'ValidationError' type when using express-validator version 7.0.1

When utilizing express-validator 7.0.1, I encounter an issue trying to access the path field. The error message indicates that "Property 'path' does not exist on type 'ValidationError'.: import express, { Request, Response } from " ...

How to extract a string value from an observable array in Angular2 NativeScript?

I inserted JSON data into an observable array. My goal is to extract only the address from ShowData, specifically as a string value based on its position. ShowData.ts: class ShowData{ constructor(public id:number, public name:string, public address:s ...

The Ngrx selector fails to activate when the reducer modifies the portion

In my Angular 2 application, I heavily utilize Ngrx stores which have proven to be extremely beneficial. I have a well-structured system in place for my stores where I use selectors to retrieve specific parts of the state. Normally, all the selectors work ...

Transforming a JSON file that has been previously converted to an Observable into a TypeScript map within an Angular application

There is a json data file named dummy, with the following structure: [ {"key":"KEY1", "value":["alpha","beta","gamma"]}, {"key":"KEY2", "value":["A","B","C"]}, {"key":"KEY3", "value":["One","Foo","Bar"]} ] The goal is to convert this json f ...

Having trouble transitioning to Angular2 RC? Let's chat at [email protected] - we can help!

I encountered an error while attempting to upgrade angular2 to RC. Due to JWT dependencies on RC, I had to switch to @angular. M:\workspace\Angular2StartKit>npm install npm ERR! addLocal Could not install M:\workspace\Angular2StartK ...

Guide to modifying the root directory when deploying a Typescript cloud function from a monorepo using cloud build

Within my monorepo, I have a folder containing Typescript cloud functions that I want to deploy using GCP cloud build. Unfortunately, it appears that cloud build is unable to locate the package.json file within this specific folder. It seems to be expectin ...

The information is being properly displayed in the console, but when attempting to show it on the webpage, an ERROR occurs with the message: "Error trying to differentiate '[object Object]'"

The data is successfully displayed in the console. However, when trying to display it on the page, an error occurs: ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed services getdetails(id:number) : ...

Dealing with a 404 Error in Instagram API Using RXJS

Utilizing the Instagram API without OAuth involves using this URL: https://www.instagram.com/explore/tags/{tag}?__a=1 Everything works smoothly, I successfully obtain and manipulate the JSON data. However, when a non-existing tag is used, I encounter a 40 ...

Tips on invoking Bootstrap's collapse function without using JQuery

We are facing a challenge with our TypeScript files as we have no access to jQuery from them. Our goal is to trigger Bootstrap's collapse method... $(object).collapse(method) but without relying on jQuery. Intended Outcome //Replicates the functio ...

Subtracting Arrays Containing Duplicates

Imagine having two arrays defined like this: const A = ['Mo', 'Tu', 'We', 'Thu', 'Fr'] const B = ['Mo', 'Mo', 'Mo', 'Tu', 'Thu', 'Fr', 'Sa&ap ...

Compiling TypeScript files for Angular 2 with Atom can be quite time-consuming

Currently, I am utilizing Angular 2 RC-6 by referencing the Angular2 Documentation. However, I have encountered an issue with Atom being too slow to compile my '.ts' files. Interestingly, when I relocate my tsconfig.json file from the root folder ...

The [image link] in the NextJS image was loaded in advance using link preload, but it was not utilized within a short time after the window finished loading

While working on my blog website with NextJS, I encountered a warning in the console related to using next/image: The resource http://localhost:3000/_next/image... was preloaded using link preload but not used within a few seconds from the window's lo ...

Tips for adding and verifying arrays within forms using Angular2

Within my JavaScript model, this.profile, there exists a property named emails. This property is an array composed of objects with the properties {email, isDefault, status}. Following this, I proceed to define it as shown below: this.profileForm = this ...

The element is implicitly given an 'any' type due to the fact that a string expression cannot be used to index the following type: { "1" : { "key": string}; "2" : { "key": string};}

I have a JSON file containing IDs as keys like this: "1" : { "key": "value"}, "2" : { "key": "value"}, In my class, I import this JSON file as a data object and then use the ID passed to a method ...

Prevent the Mat Dialog from showing up depending on the situation

I am attempting to prevent a Mat Dialog from appearing unless a specific condition is met. I originally thought about using Angular Guard, but since there is no associated route with the component (besides the main webpage it's called from), that appr ...