Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(material/form-field): hiding a label after it has been shown leaves a blank space #29461

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/dev-app/input/input-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,41 @@ <h4>Custom control</h4>
</mat-card-content>
</mat-card>

<mat-card class="demo-card demo-basic">
<mat-toolbar color="primary">Without label</mat-toolbar>
<mat-card-content>
<h4>Label removed</h4>
<p>
<mat-form-field appearance="outline">
@if (hasLabel$ | async){
<mat-label>My input</mat-label>
}
<input matInput type="text" />
</mat-form-field>
</p>
<p>
<mat-form-field>
@if (hasLabel$ | async){
<mat-label>My input</mat-label>
}
<input matInput type="text" />
</mat-form-field>
</p>
<h4>No defined label</h4>
<p>
<mat-form-field appearance="outline">
<input matInput type="text"/>
</mat-form-field>
</p>
<p>
<mat-form-field>
<input matInput type="text"/>
</mat-form-field>
</p>
</mat-card-content>
</mat-card>


<mat-card class="demo-card demo-basic">
<mat-card-content>
<button (click)="showHidden = !showHidden">Show/hide hidden form-field</button>
Expand Down
8 changes: 7 additions & 1 deletion src/dev-app/input/input-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {MatIconModule} from '@angular/material/icon';
import {MatTabsModule} from '@angular/material/tabs';
import {MatToolbarModule} from '@angular/material/toolbar';
import {MatTooltipModule} from '@angular/material/tooltip';
import {BehaviorSubject} from 'rxjs';

let max = 5;

Expand Down Expand Up @@ -100,8 +101,13 @@ export class InputDemo {
fillAppearance: string;
outlineAppearance: string;

hasLabel$ = new BehaviorSubject(true);

constructor() {
setTimeout(() => this.delayedFormControl.setValue('hello'), 100);
setTimeout(() => {
this.delayedFormControl.setValue('hello');
this.hasLabel$.next(false);
}, 100);
}

addABunch(n: number) {
Expand Down
5 changes: 4 additions & 1 deletion src/material/form-field/form-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,10 @@ export class MatFormField

_hasFloatingLabel = computed(() => !!this._labelChild());

_shouldLabelFloat() {
_shouldLabelFloat(): boolean {
if (!this._hasFloatingLabel()) {
return false;
}
return this._control.shouldLabelFloat || this._shouldAlwaysFloat();
}

Expand Down
81 changes: 80 additions & 1 deletion src/material/input/input.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ describe('MatMdcInput without forms', () => {
fixture.detectChanges();

expect(formField._control.empty).toBe(false);
expect(formField._shouldLabelFloat()).toBe(true);
// should not float label if there is no label
expect(formField._shouldLabelFloat()).toBe(false);
}));

it('should not be empty when the value set before view init', fakeAsync(() => {
Expand Down Expand Up @@ -1531,6 +1532,62 @@ describe('MatFormField default options', () => {
).toBe(true);
});
});
describe('MatFormField without label', () => {
it('should not float the label when no label is defined.', () => {
let fixture = createComponent(MatInputWithoutDefinedLabel);
fixture.detectChanges();

const inputEl = fixture.debugElement.query(By.css('input'))!;
const formField = fixture.debugElement.query(By.directive(MatFormField))!
.componentInstance as MatFormField;

// Update the value of the input and set focus.
inputEl.nativeElement.value = 'Text';
fixture.detectChanges();

// should not float label if there is no label
expect(formField._shouldLabelFloat()).toBe(false);
});

it('should not float the label when the label is removed after it has been shown', () => {
let fixture = createComponent(MatInputWithCondictionalLabel);
fixture.detectChanges();
const inputEl = fixture.debugElement.query(By.css('input'))!;
const formField = fixture.debugElement.query(By.directive(MatFormField))!
.componentInstance as MatFormField;

// initially, label is present
expect(fixture.nativeElement.querySelector('label')).not.toBeNull();

// removing label after it has been shown
fixture.componentInstance.hasLabel = false;
inputEl.nativeElement.value = 'Text';
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();

// now expected to not have a label
expect(fixture.nativeElement.querySelector('label')).toBeNull();
// should not float label since there is no label
expect(formField._shouldLabelFloat()).toBe(false);
});

it('should float the label when the label is not removed', () => {
let fixture = createComponent(MatInputWithCondictionalLabel);
fixture.detectChanges();
const inputEl = fixture.debugElement.query(By.css('input'))!;
const formField = fixture.debugElement.query(By.directive(MatFormField))!
.componentInstance as MatFormField;

inputEl.nativeElement.value = 'Text';
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();

// Expected to have a label
expect(fixture.nativeElement.querySelector('label')).not.toBeNull();
// should float label since there is a label
expect(formField._shouldLabelFloat()).toBe(true);
});
});

function configureTestingModule(
component: Type<any>,
Expand Down Expand Up @@ -1787,6 +1844,28 @@ class MatInputWithDynamicLabel {
shouldFloat: 'always' | 'auto' = 'always';
}

@Component({
template: `
<mat-form-field>
<input matInput placeholder="Label">
</mat-form-field>
`,
})
class MatInputWithoutDefinedLabel {}

@Component({
template: `
<mat-form-field>
@if (hasLabel) {
<mat-label>Label</mat-label>
}
<input matInput>
</mat-form-field>`,
})
class MatInputWithCondictionalLabel {
hasLabel = true;
}

@Component({
template: `
<mat-form-field>
Expand Down
Loading