Skip to content

Commit fc30954

Browse files
committed
fix(material/form-field): add hasFloatingLabel input and update classes if mat-label is added and removed dynamically
Currently, when `mat-Label` is added dynamically initially its not visible in DOM, this fix will add/remove classes for the same. Fixes #29939
1 parent d02338b commit fc30954

File tree

5 files changed

+69
-7
lines changed

5 files changed

+69
-7
lines changed

goldens/material/form-field/index.api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ import * as i2 from '@angular/cdk/bidi';
1616
import { InjectionToken } from '@angular/core';
1717
import { NgControl } from '@angular/forms';
1818
import { Observable } from 'rxjs';
19+
import { OnChanges } from '@angular/core';
1920
import { OnDestroy } from '@angular/core';
2021
import { QueryList } from '@angular/core';
22+
import { SimpleChanges } from '@angular/core';
2123

2224
// @public
2325
export type FloatLabelType = 'always' | 'auto';

goldens/material/input/index.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { OnChanges } from '@angular/core';
2525
import { OnDestroy } from '@angular/core';
2626
import { Platform } from '@angular/cdk/platform';
2727
import { QueryList } from '@angular/core';
28+
import { SimpleChanges } from '@angular/core';
2829
import { Subject } from 'rxjs';
2930
import { WritableSignal } from '@angular/core';
3031

src/material/form-field/directives/notched-outline.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import {
1313
ElementRef,
1414
Input,
1515
NgZone,
16+
OnChanges,
17+
SimpleChanges,
1618
ViewChild,
1719
ViewEncapsulation,
1820
inject,
@@ -36,21 +38,27 @@ import {
3638
changeDetection: ChangeDetectionStrategy.OnPush,
3739
encapsulation: ViewEncapsulation.None,
3840
})
39-
export class MatFormFieldNotchedOutline implements AfterViewInit {
41+
export class MatFormFieldNotchedOutline implements AfterViewInit, OnChanges {
4042
private _elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
4143
private _ngZone = inject(NgZone);
4244

4345
/** Whether the notch should be opened. */
4446
@Input('matFormFieldNotchedOutlineOpen') open: boolean = false;
4547

48+
/** Whether the floating label is present. */
49+
@Input('matFormFieldHasFloatingLabel') hasFloatingLabel: boolean = false;
50+
4651
@ViewChild('notch') _notch: ElementRef<HTMLElement>;
4752

48-
ngAfterViewInit(): void {
49-
const element = this._elementRef.nativeElement;
50-
const label = element.querySelector<HTMLElement>('.mdc-floating-label');
53+
/** Gets the HTML element for the floating label. */
54+
get element(): HTMLElement {
55+
return this._elementRef.nativeElement;
56+
}
5157

58+
ngAfterViewInit(): void {
59+
const label = this.element.querySelector<HTMLElement>('.mdc-floating-label');
5260
if (label) {
53-
element.classList.add('mdc-notched-outline--upgraded');
61+
this.element.classList.add('mdc-notched-outline--upgraded');
5462

5563
if (typeof requestAnimationFrame === 'function') {
5664
label.style.transitionDuration = '0s';
@@ -59,7 +67,18 @@ export class MatFormFieldNotchedOutline implements AfterViewInit {
5967
});
6068
}
6169
} else {
62-
element.classList.add('mdc-notched-outline--no-label');
70+
this.element.classList.add('mdc-notched-outline--no-label');
71+
}
72+
}
73+
74+
ngOnChanges(changes: SimpleChanges) {
75+
if (
76+
changes['hasFloatingLabel'] &&
77+
this.hasFloatingLabel &&
78+
this.element.classList.contains('mdc-notched-outline--no-label')
79+
) {
80+
this.element.classList.add('mdc-notched-outline--upgraded');
81+
this.element.classList.remove('mdc-notched-outline--no-label');
6382
}
6483
}
6584

src/material/form-field/form-field.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@
5050
}
5151
<div class="mat-mdc-form-field-flex">
5252
@if (_hasOutline()) {
53-
<div matFormFieldNotchedOutline [matFormFieldNotchedOutlineOpen]="_shouldLabelFloat()">
53+
<div
54+
matFormFieldNotchedOutline
55+
[matFormFieldNotchedOutlineOpen]="_shouldLabelFloat()"
56+
[matFormFieldHasFloatingLabel]="_hasFloatingLabel()">
5457
@if (!_forceDisplayInfixLabel()) {
5558
<ng-template [ngTemplateOutlet]="labelTemplate"></ng-template>
5659
}

src/material/input/input.spec.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,27 @@ describe('MatMdcInput without forms', () => {
625625
expect(input.getAttribute('aria-describedby')).toBe(`initial ${hintId}`);
626626
}));
627627

628+
it('should show outline label correctly based on initial condition to false', fakeAsync(() => {
629+
const fixture = TestBed.createComponent(MatInputOutlineWithConditionalLabel);
630+
fixture.detectChanges();
631+
tick(16);
632+
633+
const notchedOutline: HTMLElement = fixture.debugElement.query(
634+
By.css('.mdc-notched-outline'),
635+
).nativeElement;
636+
637+
expect(notchedOutline.classList).toContain('mdc-notched-outline--no-label');
638+
expect(notchedOutline.classList).not.toContain('mdc-notched-outline--upgraded');
639+
640+
fixture.componentInstance.showLabel = true;
641+
fixture.changeDetectorRef.markForCheck();
642+
fixture.detectChanges();
643+
tick(16);
644+
645+
expect(notchedOutline.classList).not.toContain('mdc-notched-outline--no-label');
646+
expect(notchedOutline.classList).toContain('mdc-notched-outline--upgraded');
647+
}));
648+
628649
it('supports user binding to aria-describedby', fakeAsync(() => {
629650
const fixture = TestBed.createComponent(MatInputWithSubscriptAndAriaDescribedBy);
630651

@@ -2170,6 +2191,22 @@ class MatInputWithAppearance {
21702191
appearance: MatFormFieldAppearance;
21712192
}
21722193

2194+
@Component({
2195+
template: `
2196+
<mat-form-field appearance="outline">
2197+
@if(showLabel) {
2198+
<mat-label>My Label</mat-label>
2199+
}
2200+
<input matInput placeholder="Placeholder">
2201+
</mat-form-field>
2202+
`,
2203+
imports: [MatInputModule],
2204+
})
2205+
class MatInputOutlineWithConditionalLabel {
2206+
@ViewChild(MatFormField) formField: MatFormField;
2207+
showLabel: boolean = false;
2208+
}
2209+
21732210
@Component({
21742211
template: `
21752212
<mat-form-field [subscriptSizing]="sizing">

0 commit comments

Comments
 (0)