Skip to content

Commit b0604f0

Browse files
committed
Use afterRender instead
1 parent 7dd8200 commit b0604f0

File tree

1 file changed

+58
-50
lines changed

1 file changed

+58
-50
lines changed

src/material/form-field/form-field.ts

Lines changed: 58 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {
1919
ElementRef,
2020
Inject,
2121
InjectionToken,
22+
Injector,
23+
inject,
2224
Input,
2325
NgZone,
2426
OnDestroy,
@@ -27,9 +29,7 @@ import {
2729
ViewChild,
2830
ViewEncapsulation,
2931
ANIMATION_MODULE_TYPE,
30-
afterNextRender,
31-
inject,
32-
Injector,
32+
afterRender,
3333
} from '@angular/core';
3434
import {AbstractControlDirective} from '@angular/forms';
3535
import {ThemePalette} from '@angular/material/core';
@@ -248,7 +248,7 @@ export class MatFormField
248248
// If the appearance has been switched to `outline`, the label offset needs to be updated.
249249
// The update can happen once the view has been re-checked, but not immediately because
250250
// the view has not been updated and the notched-outline floating label is not present.
251-
this._updateOutlineLabelOffsetAfterNextRender();
251+
this._needsOutlineLabelOffsetUpdate = true;
252252
}
253253
}
254254
private _appearance: MatFormFieldAppearance = DEFAULT_APPEARANCE;
@@ -303,6 +303,7 @@ export class MatFormField
303303
private _destroyed = new Subject<void>();
304304
private _isFocused: boolean | null = null;
305305
private _explicitFormFieldControl: MatFormFieldControl<any>;
306+
private _needsOutlineLabelOffsetUpdate = false;
306307

307308
private _injector = inject(Injector);
308309

@@ -496,10 +497,26 @@ export class MatFormField
496497
* trigger the label offset update.
497498
*/
498499
private _initializeOutlineLabelOffsetSubscriptions() {
499-
this._prefixChildren.changes.subscribe(() => this._updateOutlineLabelOffsetAfterNextRender());
500+
// Whenever the prefix changes, schedule an update of the label offset.
501+
this._prefixChildren.changes.subscribe(() => (this._needsOutlineLabelOffsetUpdate = true));
502+
503+
// TODO(mmalerba): Split this into separate `afterRender` calls using the
504+
// `EarlyRead` and `Write` phases.
505+
afterRender(
506+
() => {
507+
if (this._needsOutlineLabelOffsetUpdate) {
508+
this._needsOutlineLabelOffsetUpdate = false;
509+
this._updateOutlineLabelOffset();
510+
}
511+
},
512+
{
513+
injector: this._injector,
514+
},
515+
);
516+
500517
this._dir.change
501518
.pipe(takeUntil(this._destroyed))
502-
.subscribe(() => this._updateOutlineLabelOffsetAfterNextRender());
519+
.subscribe(() => (this._needsOutlineLabelOffsetUpdate = true));
503520
}
504521

505522
/** Whether the floating label should always float or not. */
@@ -643,50 +660,41 @@ export class MatFormField
643660
* not need to do this because they use a fixed width for prefixes. Hence, they can simply
644661
* incorporate the horizontal offset into their default text-field styles.
645662
*/
646-
private _updateOutlineLabelOffsetAfterNextRender() {
647-
// TODO(mmalerba): Split this into separate `afterNextRender` calls using the `EarlyRead` and
648-
// `Write` phases.
649-
afterNextRender(
650-
() => {
651-
if (!this._hasOutline() || !this._floatingLabel) {
652-
return;
653-
}
654-
const floatingLabel = this._floatingLabel.element;
655-
// If no prefix is displayed, reset the outline label offset from potential
656-
// previous label offset updates.
657-
if (!(this._iconPrefixContainer || this._textPrefixContainer)) {
658-
floatingLabel.style.transform = '';
659-
return;
660-
}
661-
// If the form field is not attached to the DOM yet (e.g. in a tab), we defer
662-
// the label offset update until after the next render.
663-
if (!this._isAttachedToDom()) {
664-
this._updateOutlineLabelOffsetAfterNextRender();
665-
return;
666-
}
667-
const iconPrefixContainer = this._iconPrefixContainer?.nativeElement;
668-
const textPrefixContainer = this._textPrefixContainer?.nativeElement;
669-
const iconPrefixContainerWidth = iconPrefixContainer?.getBoundingClientRect().width ?? 0;
670-
const textPrefixContainerWidth = textPrefixContainer?.getBoundingClientRect().width ?? 0;
671-
// If the directionality is RTL, the x-axis transform needs to be inverted. This
672-
// is because `transformX` does not change based on the page directionality.
673-
const negate = this._dir.value === 'rtl' ? '-1' : '1';
674-
const prefixWidth = `${iconPrefixContainerWidth + textPrefixContainerWidth}px`;
675-
const labelOffset = `var(--mat-mdc-form-field-label-offset-x, 0px)`;
676-
const labelHorizontalOffset = `calc(${negate} * (${prefixWidth} + ${labelOffset}))`;
677-
678-
// Update the translateX of the floating label to account for the prefix container,
679-
// but allow the CSS to override this setting via a CSS variable when the label is
680-
// floating.
681-
floatingLabel.style.transform = `var(
682-
--mat-mdc-form-field-label-transform,
683-
${FLOATING_LABEL_DEFAULT_DOCKED_TRANSFORM} translateX(${labelHorizontalOffset})
684-
)`;
685-
},
686-
{
687-
injector: this._injector,
688-
},
689-
);
663+
private _updateOutlineLabelOffset() {
664+
if (!this._hasOutline() || !this._floatingLabel) {
665+
return;
666+
}
667+
const floatingLabel = this._floatingLabel.element;
668+
// If no prefix is displayed, reset the outline label offset from potential
669+
// previous label offset updates.
670+
if (!(this._iconPrefixContainer || this._textPrefixContainer)) {
671+
floatingLabel.style.transform = '';
672+
return;
673+
}
674+
// If the form field is not attached to the DOM yet (e.g. in a tab), we defer
675+
// the label offset update until the zone stabilizes.
676+
if (!this._isAttachedToDom()) {
677+
this._needsOutlineLabelOffsetUpdate = true;
678+
return;
679+
}
680+
const iconPrefixContainer = this._iconPrefixContainer?.nativeElement;
681+
const textPrefixContainer = this._textPrefixContainer?.nativeElement;
682+
const iconPrefixContainerWidth = iconPrefixContainer?.getBoundingClientRect().width ?? 0;
683+
const textPrefixContainerWidth = textPrefixContainer?.getBoundingClientRect().width ?? 0;
684+
// If the directionality is RTL, the x-axis transform needs to be inverted. This
685+
// is because `transformX` does not change based on the page directionality.
686+
const negate = this._dir.value === 'rtl' ? '-1' : '1';
687+
const prefixWidth = `${iconPrefixContainerWidth + textPrefixContainerWidth}px`;
688+
const labelOffset = `var(--mat-mdc-form-field-label-offset-x, 0px)`;
689+
const labelHorizontalOffset = `calc(${negate} * (${prefixWidth} + ${labelOffset}))`;
690+
691+
// Update the translateX of the floating label to account for the prefix container,
692+
// but allow the CSS to override this setting via a CSS variable when the label is
693+
// floating.
694+
floatingLabel.style.transform = `var(
695+
--mat-mdc-form-field-label-transform,
696+
${FLOATING_LABEL_DEFAULT_DOCKED_TRANSFORM} translateX(${labelHorizontalOffset})
697+
)`;
690698
}
691699

692700
/** Checks whether the form field is attached to the DOM. */

0 commit comments

Comments
 (0)