diff --git a/src/components-examples/material/select/index.ts b/src/components-examples/material/select/index.ts index 594bd086b375..d0bad800d5db 100644 --- a/src/components-examples/material/select/index.ts +++ b/src/components-examples/material/select/index.ts @@ -1,9 +1,12 @@ export {SelectCustomTriggerExample} from './select-custom-trigger/select-custom-trigger-example'; export {SelectDisabledExample} from './select-disabled/select-disabled-example'; +export {SelectDisabledSignalFormExample} from './select-disabled-signal-form/select-disabled-signal-form-example'; export {SelectErrorStateMatcherExample} from './select-error-state-matcher/select-error-state-matcher-example'; export {SelectFormExample} from './select-form/select-form-example'; +export {SelectFormSignalFormExample} from './select-form-signal-form/select-form-signal-form-example'; export {SelectHintErrorExample} from './select-hint-error/select-hint-error-example'; export {SelectMultipleExample} from './select-multiple/select-multiple-example'; +export {SelectMultipleSignalFormExample} from './select-multiple-signal-form/select-multiple-signal-form-example'; export {SelectNoRippleExample} from './select-no-ripple/select-no-ripple-example'; export {SelectOptgroupExample} from './select-optgroup/select-optgroup-example'; export {SelectOverviewExample} from './select-overview/select-overview-example'; @@ -13,4 +16,5 @@ export {SelectValueBindingExample} from './select-value-binding/select-value-bin export {SelectReactiveFormExample} from './select-reactive-form/select-reactive-form-example'; export {SelectInitialValueExample} from './select-initial-value/select-initial-value-example'; export {SelectSelectableNullExample} from './select-selectable-null/select-selectable-null-example'; +export {SelectHintErrorSignalFormExample} from './select-hint-error-signal-form/select-hint-error-signal-form-example'; export {SelectHarnessExample} from './select-harness/select-harness-example'; diff --git a/src/components-examples/material/select/select-disabled-signal-form/select-disabled-signal-form-example.html b/src/components-examples/material/select/select-disabled-signal-form/select-disabled-signal-form-example.html new file mode 100644 index 000000000000..a605f2d0eca4 --- /dev/null +++ b/src/components-examples/material/select/select-disabled-signal-form/select-disabled-signal-form-example.html @@ -0,0 +1,26 @@ +

+ Disable select +

+ +

mat-select

+ + Choose an option + + Option 1 + Option 2 (disabled) + Option 3 + + + +

native html select

+ + Choose an option + + + diff --git a/src/components-examples/material/select/select-disabled-signal-form/select-disabled-signal-form-example.ts b/src/components-examples/material/select/select-disabled-signal-form/select-disabled-signal-form-example.ts new file mode 100644 index 000000000000..595ebe764984 --- /dev/null +++ b/src/components-examples/material/select/select-disabled-signal-form/select-disabled-signal-form-example.ts @@ -0,0 +1,20 @@ +import {Component, signal} from '@angular/core'; +import {disabled, form, FormField} from '@angular/forms/signals'; +import {MatInputModule} from '@angular/material/input'; +import {MatSelectModule} from '@angular/material/select'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {MatCheckboxModule} from '@angular/material/checkbox'; + +/** @title Disabled select (signal forms) */ +@Component({ + selector: 'select-disabled-signal-form-example', + templateUrl: 'select-disabled-signal-form-example.html', + imports: [MatCheckboxModule, FormField, MatFormFieldModule, MatSelectModule, MatInputModule], +}) +export class SelectDisabledSignalFormExample { + // TODO - more distinct name? + protected form = form(signal({option: '', vehicle: '', disableField: false}), p => { + disabled(p.option, {when: ({valueOf}) => valueOf(p.disableField)}); + disabled(p.vehicle, {when: ({valueOf}) => valueOf(p.disableField)}); + }); +} diff --git a/src/components-examples/material/select/select-form-signal-form/select-form-signal-form-example.html b/src/components-examples/material/select/select-form-signal-form/select-form-signal-form-example.html new file mode 100644 index 000000000000..e33133c6dc4f --- /dev/null +++ b/src/components-examples/material/select/select-form-signal-form/select-form-signal-form-example.html @@ -0,0 +1,23 @@ +
+

mat-select

+ + Favorite food + + @for (food of foods; track food) { + {{food.viewValue}} + } + + +

Selected food: {{selectedValue().value()}}

+

native html select

+ + Favorite car + + +

Selected car: {{selectedCar().value()}}

+
diff --git a/src/components-examples/material/select/select-form-signal-form/select-form-signal-form-example.ts b/src/components-examples/material/select/select-form-signal-form/select-form-signal-form-example.ts new file mode 100644 index 000000000000..259d8ff11859 --- /dev/null +++ b/src/components-examples/material/select/select-form-signal-form/select-form-signal-form-example.ts @@ -0,0 +1,40 @@ +import {Component, signal} from '@angular/core'; +import {MatInputModule} from '@angular/material/input'; +import {MatSelectModule} from '@angular/material/select'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {form, FormField} from '@angular/forms/signals'; + +interface Food { + value: string; + viewValue: string; +} + +interface Car { + value: string; + viewValue: string; +} + +/** + * @title Select in a form (signal forms) + */ +@Component({ + selector: 'select-form-signal-form-example', + templateUrl: 'select-form-signal-form-example.html', + imports: [FormField, MatFormFieldModule, MatSelectModule, MatInputModule], +}) +export class SelectFormSignalFormExample { + protected selectedValue = form(signal('')); + protected selectedCar = form(signal('')); + + protected foods: Food[] = [ + {value: 'steak-0', viewValue: 'Steak'}, + {value: 'pizza-1', viewValue: 'Pizza'}, + {value: 'tacos-2', viewValue: 'Tacos'}, + ]; + + protected cars: Car[] = [ + {value: 'volvo', viewValue: 'Volvo'}, + {value: 'saab', viewValue: 'Saab'}, + {value: 'mercedes', viewValue: 'Mercedes'}, + ]; +} diff --git a/src/components-examples/material/select/select-form/select-form-example.ts b/src/components-examples/material/select/select-form/select-form-example.ts index 4adec595ab14..5ef030ca4004 100644 --- a/src/components-examples/material/select/select-form/select-form-example.ts +++ b/src/components-examples/material/select/select-form/select-form-example.ts @@ -15,7 +15,7 @@ interface Car { } /** - * @title Select in a form + * @title Select in a form (template-driven forms) */ @Component({ selector: 'select-form-example', diff --git a/src/components-examples/material/select/select-hint-error-signal-form/select-hint-error-signal-form-example.html b/src/components-examples/material/select/select-hint-error-signal-form/select-hint-error-signal-form-example.html new file mode 100644 index 000000000000..1cdd995d3eca --- /dev/null +++ b/src/components-examples/material/select/select-hint-error-signal-form/select-hint-error-signal-form-example.html @@ -0,0 +1,32 @@ +

mat select

+ + Favorite animal + + -- + @for (animal of animals; track animal) { + {{animal.name}} + } + + @if (animalControl().getError('required')) { + Please choose an animal + } + @if (animalSound(); as animalSound) { + {{animalSound}} + } + + +

native html select

+ + Select your car (required) + + @if (selectFormControl().getError('required')) { + This field is required + } + You can pick up your favorite car here + + diff --git a/src/components-examples/material/select/select-hint-error-signal-form/select-hint-error-signal-form-example.ts b/src/components-examples/material/select/select-hint-error-signal-form/select-hint-error-signal-form-example.ts new file mode 100644 index 000000000000..c4c17448ce1c --- /dev/null +++ b/src/components-examples/material/select/select-hint-error-signal-form/select-hint-error-signal-form-example.ts @@ -0,0 +1,36 @@ +import {Component, computed, signal} from '@angular/core'; +import {MatInputModule} from '@angular/material/input'; +import {MatSelectModule} from '@angular/material/select'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {form, FormField, required} from '@angular/forms/signals'; + +interface Animal { + name: string; + sound: string; +} + +/** @title Select with form field features (signal forms) */ +@Component({ + selector: 'select-hint-error-signal-form-example', + templateUrl: 'select-hint-error-signal-form-example.html', + imports: [MatFormFieldModule, MatSelectModule, FormField, MatInputModule], +}) +export class SelectHintErrorSignalFormExample { + protected animalControl = form(signal(''), p => { + required(p); + }); + protected selectFormControl = form(signal(''), p => { + required(p); + }); + + protected animalSound = computed( + () => this.animals.find(a => a.name === this.animalControl().value())?.sound, + ); + + protected animals: Animal[] = [ + {name: 'Dog', sound: 'Woof!'}, + {name: 'Cat', sound: 'Meow!'}, + {name: 'Cow', sound: 'Moo!'}, + {name: 'Fox', sound: 'Wa-pa-pa-pa-pa-pa-pow!'}, + ]; +} diff --git a/src/components-examples/material/select/select-multiple-signal-form/select-multiple-signal-form-example.html b/src/components-examples/material/select/select-multiple-signal-form/select-multiple-signal-form-example.html new file mode 100644 index 000000000000..aeac18bd98e8 --- /dev/null +++ b/src/components-examples/material/select/select-multiple-signal-form/select-multiple-signal-form-example.html @@ -0,0 +1,8 @@ + + Toppings + + @for (topping of toppingList; track topping) { + {{topping}} + } + + diff --git a/src/components-examples/material/select/select-multiple-signal-form/select-multiple-signal-form-example.ts b/src/components-examples/material/select/select-multiple-signal-form/select-multiple-signal-form-example.ts new file mode 100644 index 000000000000..6c26aaca7d2d --- /dev/null +++ b/src/components-examples/material/select/select-multiple-signal-form/select-multiple-signal-form-example.ts @@ -0,0 +1,15 @@ +import {Component, signal} from '@angular/core'; +import {MatSelectModule} from '@angular/material/select'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {form, FormField} from '@angular/forms/signals'; + +/** @title Select with multiple selection (signal forms) */ +@Component({ + selector: 'select-multiple-signal-form-example', + templateUrl: 'select-multiple-signal-form-example.html', + imports: [MatFormFieldModule, MatSelectModule, FormField], +}) +export class SelectMultipleSignalFormExample { + toppings = form(signal([])); + toppingList = ['Extra cheese', 'Mushroom', 'Onion', 'Pepperoni', 'Sausage', 'Tomato'] as const; +} diff --git a/src/components-examples/material/select/select-multiple/select-multiple-example.ts b/src/components-examples/material/select/select-multiple/select-multiple-example.ts index 43a6e964d793..ca6958aa24b7 100644 --- a/src/components-examples/material/select/select-multiple/select-multiple-example.ts +++ b/src/components-examples/material/select/select-multiple/select-multiple-example.ts @@ -10,6 +10,6 @@ import {MatFormFieldModule} from '@angular/material/form-field'; imports: [MatFormFieldModule, MatSelectModule, FormsModule, ReactiveFormsModule], }) export class SelectMultipleExample { - toppings = new FormControl(''); + toppings = new FormControl([]); toppingList: string[] = ['Extra cheese', 'Mushroom', 'Onion', 'Pepperoni', 'Sausage', 'Tomato']; } diff --git a/src/material/select/select.md b/src/material/select/select.md index 27b591e1fc40..69732ddeff5d 100644 --- a/src/material/select/select.md +++ b/src/material/select/select.md @@ -35,7 +35,7 @@ Including `FormField` (signal forms), `FormsModule` (`NgModel`) and `ReactiveFor `compareWith` function. (Additional information about using a custom `compareWith` function can be found in the [Angular forms documentation](https://angular.dev/api/forms/SelectControlValueAccessor#compareWith)). - + ### Form field features @@ -44,7 +44,7 @@ include error messages, hint text, prefix & suffix, and theming. For additional these features, see the [form field documentation](https://material.angular.dev/components/form-field/overview). - + ### Setting a static placeholder @@ -58,11 +58,17 @@ In some cases that `` may use the placeholder as the label (see It is possible to disable the entire select or individual options in the select by using the disabled property on the `` or ``, and the disabled property should not be bound +to the selects in the template. However, individual `