Skip to content
Open
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
@@ -0,0 +1,3 @@
.example-section {
margin: 12px 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<section class="example-section">
<h4>Select your toppings:</h4>
<p><mat-checkbox [formField]="toppingsForm.pepperoni">Pepperoni</mat-checkbox></p>
<p><mat-checkbox [formField]="toppingsForm.extracheese">Extra Cheese</mat-checkbox></p>
<p><mat-checkbox [formField]="toppingsForm.mushroom">Mushroom</mat-checkbox></p>
</section>

<section class="example-section">
<h4>You chose:</h4>
{{toppingsForm().value() | json}}
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {JsonPipe} from '@angular/common';
import {Component, signal} from '@angular/core';
import {form, FormField} from '@angular/forms/signals';
import {MatCheckboxModule} from '@angular/material/checkbox';

/** @title Checkboxes with signal forms */
@Component({
selector: 'checkbox-signal-forms-example',
templateUrl: 'checkbox-signal-forms-example.html',
styleUrl: 'checkbox-signal-forms-example.css',
imports: [FormField, MatCheckboxModule, JsonPipe],
})
export class CheckboxSignalFormsExample {
readonly toppingsFormModel = signal({
pepperoni: false,
extracheese: false,
mushroom: false,
});

readonly toppingsForm = form(this.toppingsFormModel);
}
1 change: 1 addition & 0 deletions src/components-examples/material/checkbox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export {CheckboxConfigurableExample} from './checkbox-configurable/checkbox-conf
export {CheckboxHarnessExample} from './checkbox-harness/checkbox-harness-example';
export {CheckboxOverviewExample} from './checkbox-overview/checkbox-overview-example';
export {CheckboxReactiveFormsExample} from './checkbox-reactive-forms/checkbox-reactive-forms-example';
export {CheckboxSignalFormsExample} from './checkbox-signal-forms/checkbox-signal-forms-example';
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<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) {
@for (keyword of keywords(); track $index) {
<mat-chip-row (removed)="removeKeyword(keyword)">
{{keyword}}
<button matChipRemove [attr.aria-label]="'remove ' + keyword">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.example-button-container > button {
margin: 0 12px;
}

.example-form-field {
width: 100%;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<div class="example-button-container">
<button matButton="elevated" (click)="keywordsFormModel.update(m => ({ ...m, enabled: false }))">
Disable form control
</button>
<button matButton="elevated" (click)="keywordsFormModel.update(m => ({ ...m, enabled: true }))">
Enable form control
</button>
</div>
<p>
<em>Enter video keywords</em>
</p>
<mat-form-field class="example-form-field">
<mat-label>Video keywords</mat-label>
<mat-chip-grid #chipGrid aria-label="Enter keywords" [formField]="keywordsForm.words">
@for (keyword of keywordsForm.words().value(); track $index) {
<mat-chip-row (removed)="removeKeyword(keyword)">
{{ keyword }}
<button matChipRemove [attr.aria-label]="'remove ' + keyword">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>
}
</mat-chip-grid>
<input
placeholder="New keyword..."
[matChipInputFor]="chipGrid"
(matChipInputTokenEnd)="add($event)"
/>
</mat-form-field>

<p><strong>The following keywords are entered:</strong> {{ keywordsForm.words().value() }}</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {LiveAnnouncer} from '@angular/cdk/a11y';
import {Component, inject, signal} from '@angular/core';
import {disabled, form, FormField} from '@angular/forms/signals';
import {MatButtonModule} from '@angular/material/button';
import {MatChipInputEvent, MatChipsModule} from '@angular/material/chips';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatIconModule} from '@angular/material/icon';

/**
* @title Chips with form field
*/
@Component({
selector: 'chips-form-field-example',
templateUrl: 'chips-form-field-example.html',
styleUrl: 'chips-form-field-example.css',
imports: [FormField, MatButtonModule, MatFormFieldModule, MatChipsModule, MatIconModule],
})
export class ChipsFormFieldExample {
readonly keywordsFormModel = signal({
words: ['angular', 'how-to', 'tutorial', 'accessibility'],
enabled: true,
});

readonly keywordsForm = form(this.keywordsFormModel, p => {
disabled(p, {
when: ({valueOf}) => !valueOf(p.enabled),
});
});

announcer = inject(LiveAnnouncer);

protected removeKeyword(keyword: string) {
this.keywordsFormModel.update(keywords => {
const index = keywords.words.indexOf(keyword);
if (index < 0) {
return keywords;
}

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

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

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

// Clear the input value
event.chipInput!.clear();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ <h4>Chips inside of a Reactive form</h4>
<mat-form-field class="example-form-field">
<mat-label>Video keywords</mat-label>
<mat-chip-grid #reactiveChipGrid aria-label="Enter reactive form keywords" [formControl]="formControl">
@for (keyword of formControl.value; track keyword) {
@for (keyword of formControl.value; track $index) {
<mat-chip-row (removed)="removeKeyword(keyword)">
{{keyword}}
<button matChipRemove [attr.aria-label]="'remove reactive form' + keyword">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.example-form-field {
width: 100%;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<section>
<h4>Chips inside of a Signal form</h4>
<mat-form-field class="example-form-field">
<mat-label>Video keywords</mat-label>
<mat-chip-grid #signalChipGrid aria-label="Enter signal form keywords" [formField]="keywordsForm">
@for (keyword of keywordsForm().value(); track $index) {
<mat-chip-row (removed)="removeKeyword(keyword)">
{{keyword}}
<button matChipRemove [attr.aria-label]="'remove signal form' + keyword">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>
}
</mat-chip-grid>
<input
placeholder="New keyword..."
[matChipInputFor]="signalChipGrid"
(matChipInputTokenEnd)="addKeyword($event)"
/>
</mat-form-field>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {LiveAnnouncer} from '@angular/cdk/a11y';
import {Component, inject, signal} from '@angular/core';
import {form, FormField} from '@angular/forms/signals';
import {MatButtonModule} from '@angular/material/button';
import {MatChipInputEvent, MatChipsModule} from '@angular/material/chips';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatIconModule} from '@angular/material/icon';

/**
* @title Chips in signal forms
*/
@Component({
selector: 'chips-signal-form-example',
templateUrl: 'chips-signal-form-example.html',
styleUrl: 'chips-signal-form-example.css',
imports: [FormField, MatButtonModule, MatFormFieldModule, MatChipsModule, MatIconModule],
})
export class ChipsSignalFormExample {
private _announcer = inject(LiveAnnouncer);

readonly keywordsFormModel = signal(['angular', 'how-to', 'tutorial', 'accessibility']);

readonly keywordsForm = form(this.keywordsFormModel);

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

if (value) {
this.keywordsFormModel.update(model => [...model, value]);
this._announcer.announce(`added ${value} to signal form`);
}

event.chipInput.clear();
}

protected removeKeyword(keyword: string) {
const keywords = this.keywordsForm().value();
const index = keywords.lastIndexOf(keyword);

if (index > -1) {
keywords.splice(index, 1);
this.keywordsFormModel.set(keywords);
this._announcer.announce(`removed ${keyword} from signal form`);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ <h4>Chips inside of a Template-driven form</h4>
<mat-form-field class="example-form-field">
<mat-label>Video keywords</mat-label>
<mat-chip-grid #templateChipGrid aria-label="Enter template form keywords" [(ngModel)]="keywords">
@for (keyword of keywords(); track keyword) {
@for (keyword of keywords(); track $index) {
<mat-chip-row (removed)="removeKeyword(keyword)">
{{keyword}}
<button matChipRemove [attr.aria-label]="'remove template form' + keyword">
Expand Down
2 changes: 2 additions & 0 deletions src/components-examples/material/chips/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export {ChipsOverviewExample} from './chips-overview/chips-overview-example';
export {ChipsStackedExample} from './chips-stacked/chips-stacked-example';
export {ChipsHarnessExample} from './chips-harness/chips-harness-example';
export {ChipsFormControlExample} from './chips-form-control/chips-form-control-example';
export {ChipsFormFieldExample} from './chips-form-field/chips-form-field-example';
export {ChipsReactiveFormExample} from './chips-reactive-form/chips-reactive-form-example';
export {ChipsSignalFormExample} from './chips-signal-form/chips-signal-form-example';
export {ChipsTemplateFormExample} from './chips-template-form/chips-template-form-example';
export {ChipsAvatarExample} from './chips-avatar/chips-avatar-example';
5 changes: 2 additions & 3 deletions src/material/checkbox/checkbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ If you don't want the label to appear next to the checkbox, you can use
[`aria-labelledby`](https://www.w3.org/TR/wai-aria/states_and_properties#aria-labelledby) to
specify an appropriate label.

### Use with `@angular/forms`
### Use with Angular Forms

`<mat-checkbox>` is compatible with `@angular/forms` and supports both `FormsModule`
and `ReactiveFormsModule`.
`<mat-checkbox>` is compatible with `@angular/forms` and supports `FormField`, `FormsModule`, and `ReactiveFormsModule`.

### Indeterminate state

Expand Down
6 changes: 3 additions & 3 deletions src/material/chips/chips.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ Chips are always used inside a container. To create chips connected to an input

<!-- example(chips-input) -->

### Use with `@angular/forms`
Chips are compatible with `@angular/forms` and supports both `FormsModule`
and `ReactiveFormsModule`.
### Use with Angular Forms
Chips are compatible with `@angular/forms` and supports `FormField`, `FormsModule`, and `ReactiveFormsModule`.

<!-- example(chips-signal-form) -->
<!-- example(chips-template-form) -->
<!-- example(chips-reactive-form) -->

Expand Down
Loading