Skip to content

Commit 6775ea6

Browse files
committed
fix(form-field): outline gap not calculated when appearance is provided through DI
Fixes the outline gap not being calculated if the `appearance` is set through the default options, because it doesn't go through the setter and we're not guaranteed for the `MutationObserver` callback to fire at the right time. Fixes #12765.
1 parent dad0ed0 commit 6775ea6

File tree

2 files changed

+57
-10
lines changed

2 files changed

+57
-10
lines changed

src/lib/form-field/form-field.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,12 @@ export class MatFormField extends _MatFormFieldMixinBase
144144

145145
/** The form-field appearance style. */
146146
@Input()
147-
get appearance(): MatFormFieldAppearance {
148-
return this._appearance || this._defaultOptions && this._defaultOptions.appearance || 'legacy';
149-
}
147+
get appearance(): MatFormFieldAppearance { return this._appearance; }
150148
set appearance(value: MatFormFieldAppearance) {
151149
const oldValue = this._appearance;
152-
this._appearance = value;
150+
151+
this._appearance = value || (this._defaults && this._defaults.appearance) || 'legacy';
152+
153153
if (this._appearance === 'outline' && oldValue !== value) {
154154
// @breaking-change 7.0.0 Remove this check and else block once _ngZone is required.
155155
if (this._ngZone) {
@@ -245,8 +245,8 @@ export class MatFormField extends _MatFormFieldMixinBase
245245
private _changeDetectorRef: ChangeDetectorRef,
246246
@Optional() @Inject(MAT_LABEL_GLOBAL_OPTIONS) labelOptions: LabelOptions,
247247
@Optional() private _dir: Directionality,
248-
@Optional() @Inject(MAT_FORM_FIELD_DEFAULT_OPTIONS) private _defaultOptions:
249-
MatFormFieldDefaultOptions,
248+
@Optional() @Inject(MAT_FORM_FIELD_DEFAULT_OPTIONS)
249+
private _defaults: MatFormFieldDefaultOptions,
250250
// @breaking-change 7.0.0 _platform, _ngZone and _animationMode to be made required.
251251
private _platform?: Platform,
252252
private _ngZone?: NgZone,
@@ -256,6 +256,9 @@ export class MatFormField extends _MatFormFieldMixinBase
256256
this._labelOptions = labelOptions ? labelOptions : {};
257257
this.floatLabel = this._labelOptions.float || 'auto';
258258
this._animationsEnabled = _animationMode !== 'NoopAnimations';
259+
260+
// Set the default through here so we invoke the setter on the first run.
261+
this.appearance = (_defaults && _defaults.appearance) ? _defaults.appearance : 'legacy';
259262
}
260263

261264
/**

src/lib/input/input.spec.ts

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import {Platform, PlatformModule} from '@angular/cdk/platform';
2-
import {createFakeEvent, dispatchFakeEvent, wrappedErrorMessage} from '@angular/cdk/testing';
3-
import {ChangeDetectionStrategy, Component, ViewChild, Type, Provider} from '@angular/core';
2+
import {
3+
createFakeEvent,
4+
dispatchFakeEvent,
5+
wrappedErrorMessage,
6+
MockNgZone,
7+
} from '@angular/cdk/testing';
8+
import {ChangeDetectionStrategy, Component, ViewChild, Type, Provider, NgZone} from '@angular/core';
49
import {ComponentFixture, fakeAsync, flush, TestBed} from '@angular/core/testing';
510
import {
611
FormControl,
@@ -28,10 +33,10 @@ import {
2833
} from '@angular/material/form-field';
2934
import {By} from '@angular/platform-browser';
3035
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
31-
import {MatInputModule} from './index';
32-
import {MatInput} from './input';
3336
import {MatStepperModule} from '@angular/material/stepper';
3437
import {MatTabsModule} from '@angular/material/tabs';
38+
import {MatInputModule} from './index';
39+
import {MatInput} from './input';
3540
import {MatTextareaAutosize} from './autosize';
3641

3742
describe('MatInput without forms', () => {
@@ -1170,6 +1175,35 @@ describe('MatInput with appearance', () => {
11701175
expect(parseInt(outlineGap.style.width)).toBeFalsy();
11711176
}));
11721177

1178+
it('should calculate the gaps if the default appearance is provided through DI', fakeAsync(() => {
1179+
fixture.destroy();
1180+
TestBed.resetTestingModule();
1181+
1182+
let zone: MockNgZone;
1183+
const labelFixture = createComponent(MatInputWithLabel, [
1184+
{
1185+
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
1186+
useValue: {appearance: 'outline'}
1187+
},
1188+
{
1189+
provide: NgZone,
1190+
useFactory: () => zone = new MockNgZone()
1191+
}
1192+
]);
1193+
1194+
labelFixture.detectChanges();
1195+
zone!.simulateZoneExit();
1196+
flush();
1197+
labelFixture.detectChanges();
1198+
1199+
const wrapperElement = labelFixture.nativeElement;
1200+
const outlineStart = wrapperElement.querySelector('.mat-form-field-outline-start');
1201+
const outlineGap = wrapperElement.querySelector('.mat-form-field-outline-gap');
1202+
1203+
expect(parseInt(outlineStart.style.width)).toBeGreaterThan(0);
1204+
expect(parseInt(outlineGap.style.width)).toBeGreaterThan(0);
1205+
}));
1206+
11731207
});
11741208

11751209
describe('MatFormField default options', () => {
@@ -1586,6 +1620,16 @@ class MatInputOnPush {
15861620
})
15871621
class MatInputWithReadonlyInput {}
15881622

1623+
@Component({
1624+
template: `
1625+
<mat-form-field>
1626+
<mat-label>Label</mat-label>
1627+
<input matInput>
1628+
</mat-form-field>
1629+
`
1630+
})
1631+
class MatInputWithLabel {}
1632+
15891633
@Component({
15901634
template: `
15911635
<mat-form-field [floatLabel]="floatLabel">

0 commit comments

Comments
 (0)