Skip to content

Commit 44657e2

Browse files
authored
fix(material/autocomplete): apply theme of parent form field to panel (#25983)
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 7640acd commit 44657e2

File tree

6 files changed

+72
-10
lines changed

6 files changed

+72
-10
lines changed

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

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,28 @@
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">
12-
<mat-autocomplete #reactiveAuto="matAutocomplete" [displayWith]="displayFn">
13-
<mat-option *ngFor="let state of tempStates" [value]="state">
14-
<span>{{ state.name }}</span>
15-
<span class="demo-secondary-text"> ({{ state.code }}) </span>
16-
</mat-option>
17-
</mat-autocomplete>
1812
</mat-form-field>
13+
<mat-autocomplete #reactiveAuto="matAutocomplete" [displayWith]="displayFn">
14+
<mat-option *ngFor="let state of tempStates" [value]="state">
15+
<span>{{ state.name }}</span>
16+
<span class="demo-secondary-text"> ({{ state.code }}) </span>
17+
</mat-option>
18+
</mat-autocomplete>
1919

2020
<mat-card-actions>
2121
<button mat-button (click)="stateCtrl.reset()">RESET</button>
2222
<button mat-button (click)="stateCtrl.setValue(states[10])">SET VALUE</button>
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-trigger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@ export abstract class _MatAutocompleteTriggerBase
666666

667667
this.autocomplete._setVisibility();
668668
this.autocomplete._isOpen = this._overlayAttached = true;
669+
this.autocomplete._setColor(this._formField?.color);
669670

670671
// We need to do an extra `panelOpen` check in here, because the
671672
// autocomplete won't be shown if there are no options.

src/material/autocomplete/autocomplete.spec.ts

Lines changed: 24 additions & 2 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
@@ -3403,7 +3425,6 @@ const SIMPLE_AUTOCOMPLETE_TEMPLATE = `
34033425
[matAutocompleteDisabled]="autocompleteDisabled"
34043426
[formControl]="stateCtrl">
34053427
</mat-form-field>
3406-
34073428
<mat-autocomplete [class]="panelClass" #auto="matAutocomplete" [displayWith]="displayFn"
34083429
[disableRipple]="disableRipple" [aria-label]="ariaLabel" [aria-labelledby]="ariaLabelledby"
34093430
(opened)="openedSpy()" (closed)="closedSpy()">
@@ -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: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
CanDisableRipple,
3535
_MatOptionBase,
3636
_MatOptgroupBase,
37+
ThemePalette,
3738
} from '@angular/material/core';
3839
import {ActiveDescendantKeyManager} from '@angular/cdk/a11y';
3940
import {BooleanInput, coerceBooleanProperty, coerceStringArray} from '@angular/cdk/coercion';
@@ -122,6 +123,14 @@ export abstract class _MatAutocompleteBase
122123
}
123124
_isOpen: boolean = false;
124125

126+
/** @docs-private Sets the theme color of the panel. */
127+
_setColor(value: ThemePalette) {
128+
this._color = value;
129+
this._setThemeClasses(this._classList);
130+
}
131+
/** @docs-private theme color of the panel */
132+
private _color: ThemePalette;
133+
125134
// The @ViewChild query for TemplateRef here needs to be static because some code paths
126135
// lead to the overlay being created before change detection has finished for this component.
127136
// Notably, another component may trigger `focus` on the autocomplete-trigger.
@@ -206,6 +215,7 @@ export abstract class _MatAutocompleteBase
206215
}
207216

208217
this._setVisibilityClasses(this._classList);
218+
this._setThemeClasses(this._classList);
209219
this._elementRef.nativeElement.className = '';
210220
}
211221
_classList: {[key: string]: boolean} = {};
@@ -296,6 +306,13 @@ export abstract class _MatAutocompleteBase
296306
classList[this._visibleClass] = this.showPanel;
297307
classList[this._hiddenClass] = !this.showPanel;
298308
}
309+
310+
/** Sets the theming classes on a classlist based on the theme of the panel. */
311+
private _setThemeClasses(classList: {[key: string]: boolean}) {
312+
classList['mat-primary'] = this._color === 'primary';
313+
classList['mat-warn'] = this._color === 'warn';
314+
classList['mat-accent'] = this._color === 'accent';
315+
}
299316
}
300317

301318
@Component({

tools/public_api_guard/material/autocomplete.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { QueryList } from '@angular/core';
3838
import { ScrollStrategy } from '@angular/cdk/overlay';
3939
import { SimpleChanges } from '@angular/core';
4040
import { TemplateRef } from '@angular/core';
41+
import { ThemePalette } from '@angular/material/core';
4142
import { ViewContainerRef } from '@angular/core';
4243
import { ViewportRuler } from '@angular/cdk/scrolling';
4344

@@ -123,6 +124,7 @@ export abstract class _MatAutocompleteBase extends _MatAutocompleteMixinBase imp
123124
readonly optionSelected: EventEmitter<MatAutocompleteSelectedEvent>;
124125
panel: ElementRef;
125126
panelWidth: string | number;
127+
_setColor(value: ThemePalette): void;
126128
_setScrollTop(scrollTop: number): void;
127129
_setVisibility(): void;
128130
showPanel: boolean;

0 commit comments

Comments
 (0)