Home > Software engineering >  How to make 2 chip lists interact with each other Angular Material
How to make 2 chip lists interact with each other Angular Material

Time:11-03

I'm new to angular and I wanted to implement a form that is based on chips from material UI. The user should be able to choose chips with options that they are interested in, and chosen chips should be then given on the right side, so it would be easier to deselect them.

Right now my chips on the right do update, when chips on the left are changed, but it doesn't work the other way.

I've tried to make strings in development array objects with their own ids, because I thought that would make displayed chips the same object. I've also wanted to use selected array from MatChipList but I don't know how to access it, because I have found no examples of it being used and it's only mentioned in the documentation of Material UI.

Is there any way to connect them and to gather selected chips to a form?

selecting left chips

deselecting right chips

I was thinking of using checkboxes, but the person who gave me this as a task insists on using chips.

html file:

 <div class="column">

      <mat-chip-list selectable multiple [formControl]="devControl">
        <mat-chip #chip="matChip" (click)="chip.toggleSelected(true)"
          *ngFor="let option of development"
            [selected]="option"
            [value]="option">
          <mat-icon *ngIf="chip.selected">clear</mat-icon>
          {{option}}

        </mat-chip>
      </mat-chip-list>
      <div>Value: {{chipsValue$ | async}}</div>
    </div>
    <div class="column">
      <mat-chip-list selectable multiple [formControl]="devControl">
        <mat-chip #chip="matChip" (click)="chip.toggleSelected(true)"
          *ngFor="let option of devControl.value"
            [selected]="option"
            [value]="option">
          <mat-icon *ngIf="chip.selected">clear</mat-icon>
          {{option}}

        </mat-chip>
      </mat-chip-list>
     </div>

ts file:

  development = new Set(["React", "Redux", "Webpack", "Javascript",
  "SCRUM","C#", "Docker"]);

  devControl= new FormControl('');
  chipsValue$ = this.devControl.valueChanges;

https://stackblitz.com/edit/angular-ivy-pudk8d?file=src/app/skills/skills.component.html

CodePudding user response:

I haven't used chips in particular before, but it seems the most basic thing about them is that they need text.

You presumably have a list of selectable skills (left side) in your component?

public selectableSkills: string[] = ['React', 'etc', '...'];

May or may not be a more complex object, but the basics will do.

When a user selects one, you'd like to maintain that list of selected skills?

public selectedSkills: string[] = [];

public onSkillSelected(skill: string): void {
  if (this.selectedSkills.includes(skill)) return;
  this.selectedSkills.push(skill);
}

public onSkillDeselected(skill: string): void {
  const idx = this.selectedSkills.indexOf(skill);
  if (idx < 0) return;
  this.selectedSkills.splice(idx, 1);
}

Then your right-side template can be populated purely off the selected skills, and can clear themselves off the list, whilst the left-side, populated by the available skills, can show as selected based on the existence of being selected.

Note, this can all be made tighter with more useful objects rather than bland strings.

<!--LHS-->
<mat-chip-list>
  <mat-chip *ngFor="let skill of selectableSkills
    (click)="onSkillSelected(skill)"
    [selected]="isSelected(skill)"> <!--Not shown; check if skill in the selected list-->
    {{skill}}
    <mat-icon *ngIf="isSelected(skill)"
      (click)="onSkillDeselected(skill)">
      clear
    </mat-icon>
  </mat-chip>
</mat-chip-list>

<!--RHS-->
<mat-chip-list>
  <mat-chip *ngFor="let skill of selectedSkills
    selected>
    {{skill}} 
    <mat-icon (click)="onSkillDeselected(skill)">
      clear
    </mat-icon>
  </mat-chip>
</mat-chip-list>
  • Related