Skip to content

Commit 4f55dae

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 7640acd commit 4f55dae

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)