Skip to content

Commit 862c1de

Browse files
committed
fix(material/autocomplete): apply theme of parent form field to panel
Apply the theme of the autocomplete's parent form field to its panel. Fix issue where theme color only applies to the input, and does not affect the panel.
1 parent cd52117 commit 862c1de

File tree

6 files changed

+70
-15
lines changed

6 files changed

+70
-15
lines changed

src/dev-app/autocomplete/autocomplete-demo.html

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<div>Reactive value: {{ stateCtrl.value | json }}</div>
77
<div>Reactive dirty: {{ stateCtrl.dirty }}</div>
88

9-
<mat-form-field>
9+
<mat-form-field [color]="reactiveStatesTheme">
1010
<mat-label>State</mat-label>
1111
<input matInput [matAutocomplete]="reactiveAuto" [formControl]="stateCtrl">
1212
<mat-autocomplete #reactiveAuto="matAutocomplete" [displayWith]="displayFn">
@@ -23,6 +23,11 @@
2323
<button mat-button (click)="stateCtrl.enabled ? stateCtrl.disable() : stateCtrl.enable()">
2424
TOGGLE DISABLED
2525
</button>
26+
<select [(ngModel)]="reactiveStatesTheme">
27+
<option *ngFor="let theme of availableThemes" [value]="theme.value">
28+
{{theme.name}}
29+
</option>
30+
</select>
2631
</mat-card-actions>
2732

2833
</mat-card>
@@ -33,7 +38,7 @@
3338
<div>Template-driven dirty: {{ modelDir ? modelDir.dirty : false }}</div>
3439

3540
<!-- Added an ngIf below to test that autocomplete works with ngIf -->
36-
<mat-form-field *ngIf="true">
41+
<mat-form-field *ngIf="true" [color]="templateStatesTheme">
3742
<mat-label>State</mat-label>
3843
<input matInput [matAutocomplete]="tdAuto" [(ngModel)]="currentState"
3944
(ngModelChange)="tdStates = filterStates(currentState)" [disabled]="tdDisabled">
@@ -50,6 +55,11 @@
5055
<button mat-button (click)="tdDisabled=!tdDisabled">
5156
TOGGLE DISABLED
5257
</button>
58+
<select [(ngModel)]="templateStatesTheme">
59+
<option *ngFor="let theme of availableThemes" [value]="theme.value">
60+
{{theme.name}}
61+
</option>
62+
</select>
5363
</mat-card-actions>
5464

5565
</mat-card>

src/dev-app/autocomplete/autocomplete-demo.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {MatCardModule} from '@angular/material/card';
1515
import {MatInputModule} from '@angular/material/input';
1616
import {Observable} from 'rxjs';
1717
import {map, startWith} from 'rxjs/operators';
18+
import {ThemePalette} from '@angular/material/core';
1819

1920
export interface State {
2021
code: string;
@@ -52,6 +53,15 @@ export class AutocompleteDemo {
5253

5354
tdDisabled = false;
5455

56+
reactiveStatesTheme: ThemePalette = 'primary';
57+
templateStatesTheme: ThemePalette = 'primary';
58+
59+
availableThemes = [
60+
{value: 'primary', name: 'Primary'},
61+
{value: 'accent', name: 'Accent'},
62+
{value: 'warn', name: 'Warn'},
63+
];
64+
5565
@ViewChild(NgModel) modelDir: NgModel;
5666

5767
groupedStates: StateGroup[];

src/material/autocomplete/autocomplete.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
class="mat-mdc-autocomplete-panel mdc-menu-surface mdc-menu-surface--open"
44
role="listbox"
55
[id]="id"
6+
[class]="_getPanelTheme()"
67
[ngClass]="_classList"
78
[attr.aria-label]="ariaLabel || null"
89
[attr.aria-labelledby]="_getPanelAriaLabelledby(formFieldId)"

src/material/autocomplete/autocomplete.spec.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,28 @@ describe('MDC-based MatAutocomplete', () => {
945945
});
946946
});
947947

948+
describe('with theming', () => {
949+
let fixture: ComponentFixture<SimpleAutocomplete>;
950+
951+
beforeEach(() => {
952+
fixture = createComponent(SimpleAutocomplete);
953+
fixture.detectChanges();
954+
});
955+
956+
it('should transfer the theme to the autocomplete panel', () => {
957+
fixture.componentInstance.theme = 'warn';
958+
fixture.detectChanges();
959+
960+
fixture.componentInstance.trigger.openPanel();
961+
fixture.detectChanges();
962+
963+
const panel = overlayContainerElement.querySelector(
964+
'.mat-mdc-autocomplete-panel',
965+
)! as HTMLElement;
966+
expect(panel.classList).toContain('mat-warn');
967+
});
968+
});
969+
948970
describe('keyboard events', () => {
949971
let fixture: ComponentFixture<SimpleAutocomplete>;
950972
let input: HTMLInputElement;
@@ -3393,7 +3415,7 @@ describe('MDC-based MatAutocomplete', () => {
33933415
});
33943416

33953417
const SIMPLE_AUTOCOMPLETE_TEMPLATE = `
3396-
<mat-form-field [floatLabel]="floatLabel" [style.width.px]="width">
3418+
<mat-form-field [floatLabel]="floatLabel" [style.width.px]="width" [color]="theme">
33973419
<mat-label *ngIf="hasLabel">State</mat-label>
33983420
<input
33993421
matInput
@@ -3402,19 +3424,18 @@ const SIMPLE_AUTOCOMPLETE_TEMPLATE = `
34023424
[matAutocompletePosition]="position"
34033425
[matAutocompleteDisabled]="autocompleteDisabled"
34043426
[formControl]="stateCtrl">
3427+
<mat-autocomplete [class]="panelClass" #auto="matAutocomplete" [displayWith]="displayFn"
3428+
[disableRipple]="disableRipple" [aria-label]="ariaLabel" [aria-labelledby]="ariaLabelledby"
3429+
(opened)="openedSpy()" (closed)="closedSpy()">
3430+
<mat-option
3431+
*ngFor="let state of filteredStates"
3432+
[value]="state"
3433+
[style.height.px]="state.height"
3434+
[disabled]="state.disabled">
3435+
<span>{{ state.code }}: {{ state.name }}</span>
3436+
</mat-option>
3437+
</mat-autocomplete>
34053438
</mat-form-field>
3406-
3407-
<mat-autocomplete [class]="panelClass" #auto="matAutocomplete" [displayWith]="displayFn"
3408-
[disableRipple]="disableRipple" [aria-label]="ariaLabel" [aria-labelledby]="ariaLabelledby"
3409-
(opened)="openedSpy()" (closed)="closedSpy()">
3410-
<mat-option
3411-
*ngFor="let state of filteredStates"
3412-
[value]="state"
3413-
[style.height.px]="state.height"
3414-
[disabled]="state.disabled">
3415-
<span>{{ state.code }}: {{ state.name }}</span>
3416-
</mat-option>
3417-
</mat-autocomplete>
34183439
`;
34193440

34203441
@Component({template: SIMPLE_AUTOCOMPLETE_TEMPLATE})
@@ -3431,6 +3452,7 @@ class SimpleAutocomplete implements OnDestroy {
34313452
ariaLabel: string;
34323453
ariaLabelledby: string;
34333454
panelClass = 'class-one class-two';
3455+
theme: string;
34343456
openedSpy = jasmine.createSpy('autocomplete opened spy');
34353457
closedSpy = jasmine.createSpy('autocomplete closed spy');
34363458

src/material/autocomplete/autocomplete.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
Directive,
1616
ElementRef,
1717
EventEmitter,
18+
inject,
1819
Inject,
1920
InjectionToken,
2021
Input,
@@ -35,6 +36,7 @@ import {
3536
_MatOptionBase,
3637
_MatOptgroupBase,
3738
} from '@angular/material/core';
39+
import {MatFormField, MAT_FORM_FIELD} from '@angular/material/form-field';
3840
import {ActiveDescendantKeyManager} from '@angular/cdk/a11y';
3941
import {BooleanInput, coerceBooleanProperty, coerceStringArray} from '@angular/cdk/coercion';
4042
import {Platform} from '@angular/cdk/platform';
@@ -291,6 +293,13 @@ export abstract class _MatAutocompleteBase
291293
return this.ariaLabelledby ? labelExpression + this.ariaLabelledby : labelId;
292294
}
293295

296+
/** Returns the theme to be used on the panel. */
297+
_getPanelTheme() {
298+
return this._parentFormField ? `mat-${this._parentFormField.color}` : '';
299+
}
300+
301+
protected _parentFormField: MatFormField | null = inject(MAT_FORM_FIELD, {optional: true});
302+
294303
/** Sets the autocomplete visibility classes on a classlist based on the panel is visible. */
295304
private _setVisibilityClasses(classList: {[key: string]: boolean}) {
296305
classList[this._visibleClass] = this.showPanel;

tools/public_api_guard/material/autocomplete.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ export abstract class _MatAutocompleteBase extends _MatAutocompleteMixinBase imp
104104
displayWith: ((value: any) => string) | null;
105105
_emitSelectEvent(option: _MatOptionBase): void;
106106
_getPanelAriaLabelledby(labelId: string | null): string | null;
107+
_getPanelTheme(): string;
107108
_getScrollTop(): number;
108109
protected abstract _hiddenClass: string;
109110
id: string;
@@ -123,6 +124,8 @@ export abstract class _MatAutocompleteBase extends _MatAutocompleteMixinBase imp
123124
readonly optionSelected: EventEmitter<MatAutocompleteSelectedEvent>;
124125
panel: ElementRef;
125126
panelWidth: string | number;
127+
// (undocumented)
128+
protected _parentFormField: MatFormField | null;
126129
_setScrollTop(scrollTop: number): void;
127130
_setVisibility(): void;
128131
showPanel: boolean;

0 commit comments

Comments
 (0)