Skip to content

docs(material/chips): Update chips docs & examples #29235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<mat-form-field class="example-chip-list">
<mat-label>Favorite Fruits</mat-label>
<mat-chip-grid #chipGrid aria-label="Fruit selection">
@for (fruit of fruits; track fruit) {
@for (fruit of fruits(); track $index) {
<mat-chip-row (removed)="remove(fruit)">
{{fruit}}
<button matChipRemove [attr.aria-label]="'remove ' + fruit">
Expand All @@ -11,12 +11,18 @@
</mat-chip-row>
}
</mat-chip-grid>
<input placeholder="New Fruit..." #fruitInput [formControl]="fruitCtrl"
[matChipInputFor]="chipGrid" [matAutocomplete]="auto"
<input
name="currentFruit"
placeholder="New Fruit..."
#fruitInput
[(ngModel)]="currentFruit"
[matChipInputFor]="chipGrid"
[matAutocomplete]="auto"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
(matChipInputTokenEnd)="add($event)"/>
(matChipInputTokenEnd)="add($event)"
/>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
@for (fruit of filteredFruits | async; track fruit) {
@for (fruit of filteredFruits(); track fruit) {
<mat-option [value]="fruit">{{fruit}}</mat-option>
}
</mat-autocomplete>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import {LiveAnnouncer} from '@angular/cdk/a11y';
import {COMMA, ENTER} from '@angular/cdk/keycodes';
import {Component, ElementRef, ViewChild, inject} from '@angular/core';
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatAutocompleteSelectedEvent, MatAutocompleteModule} from '@angular/material/autocomplete';
import {ChangeDetectionStrategy, Component, computed, inject, model, signal} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {MatAutocompleteModule, MatAutocompleteSelectedEvent} from '@angular/material/autocomplete';
import {MatChipInputEvent, MatChipsModule} from '@angular/material/chips';
import {Observable} from 'rxjs';
import {map, startWith} from 'rxjs/operators';
import {MatIconModule} from '@angular/material/icon';
import {AsyncPipe} from '@angular/common';
import {MatFormFieldModule} from '@angular/material/form-field';
import {LiveAnnouncer} from '@angular/cdk/a11y';
import {MatIconModule} from '@angular/material/icon';

/**
* @title Chips Autocomplete
Expand All @@ -18,67 +15,51 @@ import {LiveAnnouncer} from '@angular/cdk/a11y';
templateUrl: 'chips-autocomplete-example.html',
styleUrl: 'chips-autocomplete-example.css',
standalone: true,
imports: [
FormsModule,
MatFormFieldModule,
MatChipsModule,
MatIconModule,
MatAutocompleteModule,
ReactiveFormsModule,
AsyncPipe,
],
imports: [MatFormFieldModule, MatChipsModule, MatIconModule, MatAutocompleteModule, FormsModule],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ChipsAutocompleteExample {
separatorKeysCodes: number[] = [ENTER, COMMA];
fruitCtrl = new FormControl('');
filteredFruits: Observable<string[]>;
fruits: string[] = ['Lemon'];
allFruits: string[] = ['Apple', 'Lemon', 'Lime', 'Orange', 'Strawberry'];
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
readonly currentFruit = model('');
readonly fruits = signal(['Lemon']);
readonly allFruits: string[] = ['Apple', 'Lemon', 'Lime', 'Orange', 'Strawberry'];
readonly filteredFruits = computed(() => {
const currentFruit = this.currentFruit().toLowerCase();
return currentFruit
? this.allFruits.filter(fruit => fruit.toLowerCase().includes(currentFruit))
: this.allFruits.slice();
});

@ViewChild('fruitInput') fruitInput: ElementRef<HTMLInputElement>;

announcer = inject(LiveAnnouncer);

constructor() {
this.filteredFruits = this.fruitCtrl.valueChanges.pipe(
startWith(null),
map((fruit: string | null) => (fruit ? this._filter(fruit) : this.allFruits.slice())),
);
}
readonly announcer = inject(LiveAnnouncer);

add(event: MatChipInputEvent): void {
const value = (event.value || '').trim();

// Add our fruit
if (value) {
this.fruits.push(value);
this.fruits.update(fruits => [...fruits, value]);
}

// Clear the input value
event.chipInput!.clear();

this.fruitCtrl.setValue(null);
this.currentFruit.set('');
}

remove(fruit: string): void {
const index = this.fruits.indexOf(fruit);

if (index >= 0) {
this.fruits.splice(index, 1);
this.fruits.update(fruits => {
const index = fruits.indexOf(fruit);
if (index < 0) {
return fruits;
}

fruits.splice(index, 1);
this.announcer.announce(`Removed ${fruit}`);
}
return [...fruits];
});
}

selected(event: MatAutocompleteSelectedEvent): void {
this.fruits.push(event.option.viewValue);
this.fruitInput.nativeElement.value = '';
this.fruitCtrl.setValue(null);
}

private _filter(value: string): string[] {
const filterValue = value.toLowerCase();

return this.allFruits.filter(fruit => fruit.toLowerCase().includes(filterValue));
this.fruits.update(fruits => [...fruits, event.option.viewValue]);
this.currentFruit.set('');
event.option.deselect();
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
<mat-chip-set aria-label="Dog selection">
<mat-chip>
<img matChipAvatar src="https://material.angular.io/assets/img/examples/shiba1.jpg" alt="Photo of a Shiba Inu"/>
<img
matChipAvatar
src="https://material.angular.io/assets/img/examples/shiba1.jpg"
alt="Photo of a Shiba Inu"
/>
Dog one
</mat-chip>
<mat-chip color="primary">
<img matChipAvatar src="https://material.angular.io/assets/img/examples/shiba1.jpg" alt="Photo of a Shiba Inu"/>
<mat-chip>
<img
matChipAvatar
src="https://material.angular.io/assets/img/examples/shiba1.jpg"
alt="Photo of a Shiba Inu"
/>
Dog two
</mat-chip>
<mat-chip color="accent">
<img matChipAvatar src="https://material.angular.io/assets/img/examples/shiba1.jpg" alt="Photo of a Shiba Inu"/>
<mat-chip>
<img
matChipAvatar
src="https://material.angular.io/assets/img/examples/shiba1.jpg"
alt="Photo of a Shiba Inu"
/>
Dog three
</mat-chip>
</mat-chip-set>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Component} from '@angular/core';
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {MatChipsModule} from '@angular/material/chips';

/**
Expand All @@ -11,5 +11,6 @@ import {MatChipsModule} from '@angular/material/chips';
styleUrl: 'chips-avatar-example.css',
standalone: true,
imports: [MatChipsModule],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ChipsAvatarExample {}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
class="example-chip"
cdkDropList
cdkDropListOrientation="horizontal"
(cdkDropListDropped)="drop($event)">
@for (vegetable of vegetables; track vegetable) {
(cdkDropListDropped)="drop($event)"
>
@for (vegetable of vegetables(); track vegetable.name) {
<mat-chip class="example-box" cdkDrag>{{vegetable.name}}</mat-chip>
}
</mat-chip-set>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Component} from '@angular/core';
import {CdkDragDrop, moveItemInArray, CdkDrag, CdkDropList} from '@angular/cdk/drag-drop';
import {CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray} from '@angular/cdk/drag-drop';
import {ChangeDetectionStrategy, Component, signal} from '@angular/core';
import {MatChipsModule} from '@angular/material/chips';

export interface Vegetable {
Expand All @@ -15,18 +15,22 @@ export interface Vegetable {
styleUrl: 'chips-drag-drop-example.css',
standalone: true,
imports: [MatChipsModule, CdkDropList, CdkDrag],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ChipsDragDropExample {
vegetables: Vegetable[] = [
readonly vegetables = signal<Vegetable[]>([
{name: 'apple'},
{name: 'banana'},
{name: 'strawberry'},
{name: 'orange'},
{name: 'kiwi'},
{name: 'cherry'},
];
]);

drop(event: CdkDragDrop<Vegetable[]>) {
moveItemInArray(this.vegetables, event.previousIndex, event.currentIndex);
this.vegetables.update(vegetables => {
moveItemInArray(vegetables, event.previousIndex, event.currentIndex);
return [...vegetables];
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
</p>
<mat-form-field class="example-form-field">
<mat-label>Video keywords</mat-label>
<mat-chip-grid #chipGrid aria-label="Enter keywords" [formControl]="formControl" >
@for (keyword of keywords; track keyword) {
<mat-chip-grid #chipGrid aria-label="Enter keywords" [formControl]="formControl">
@for (keyword of keywords(); track keyword) {
<mat-chip-row (removed)="removeKeyword(keyword)">
{{keyword}}
<button matChipRemove aria-label="'remove ' + keyword">
Expand All @@ -17,11 +17,11 @@
</mat-chip-row>
}
</mat-chip-grid>
<input placeholder="New keyword..."
[matChipInputFor]="chipGrid"
(matChipInputTokenEnd)="add($event)"/>
<input
placeholder="New keyword..."
[matChipInputFor]="chipGrid"
(matChipInputTokenEnd)="add($event)"
/>
</mat-form-field>

<p>
<strong>The following keywords are entered:</strong> {{formControl.value}}
</p>
<p><strong>The following keywords are entered:</strong> {{formControl.value}}</p>
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {Component, inject} from '@angular/core';
import {LiveAnnouncer} from '@angular/cdk/a11y';
import {ChangeDetectionStrategy, Component, inject, signal} from '@angular/core';
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatButtonModule} from '@angular/material/button';
import {MatChipInputEvent, MatChipsModule} from '@angular/material/chips';
import {MatIconModule} from '@angular/material/icon';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatButtonModule} from '@angular/material/button';
import {LiveAnnouncer} from '@angular/cdk/a11y';
import {MatIconModule} from '@angular/material/icon';

/**
* @title Chips with form control
Expand All @@ -22,28 +22,33 @@ import {LiveAnnouncer} from '@angular/cdk/a11y';
ReactiveFormsModule,
MatIconModule,
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ChipsFormControlExample {
keywords = ['angular', 'how-to', 'tutorial', 'accessibility'];
formControl = new FormControl(['angular']);
readonly keywords = signal(['angular', 'how-to', 'tutorial', 'accessibility']);
readonly formControl = new FormControl(['angular']);

announcer = inject(LiveAnnouncer);

removeKeyword(keyword: string) {
const index = this.keywords.indexOf(keyword);
if (index >= 0) {
this.keywords.splice(index, 1);
this.keywords.update(keywords => {
const index = keywords.indexOf(keyword);
if (index < 0) {
return keywords;
}

keywords.splice(index, 1);
this.announcer.announce(`removed ${keyword}`);
}
return [...keywords];
});
}

add(event: MatChipInputEvent): void {
const value = (event.value || '').trim();

// Add our keyword
if (value) {
this.keywords.push(value);
this.keywords.update(keywords => [...keywords, value]);
}

// Clear the input value
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Component, signal} from '@angular/core';
import {MatIconModule} from '@angular/material/icon';
import {ChangeDetectionStrategy, Component, signal} from '@angular/core';
import {MatChipsModule} from '@angular/material/chips';
import {MatIconModule} from '@angular/material/icon';

/**
* @title Testing with MatChipsHarness
Expand All @@ -10,6 +10,7 @@ import {MatChipsModule} from '@angular/material/chips';
templateUrl: 'chips-harness-example.html',
standalone: true,
imports: [MatChipsModule, MatIconModule],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ChipsHarnessExample {
isDisabled = signal(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
<mat-form-field class="example-chip-list">
<mat-label>Favorite Fruits</mat-label>
<mat-chip-grid #chipGrid aria-label="Enter fruits">
@for (fruit of fruits; track fruit) {
@for (fruit of fruits(); track fruit) {
<mat-chip-row
(removed)="remove(fruit)"
[editable]="true"
(edited)="edit(fruit, $event)"
[aria-description]="'press enter to edit ' + fruit.name">
[aria-description]="'press enter to edit ' + fruit.name"
>
{{fruit.name}}
<button matChipRemove [attr.aria-label]="'remove ' + fruit.name">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>
}
<input placeholder="New fruit..."
[matChipInputFor]="chipGrid"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="add($event)"/>
<input
placeholder="New fruit..."
[matChipInputFor]="chipGrid"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="add($event)"
/>
</mat-chip-grid>
</mat-form-field>
Loading
Loading