-
Notifications
You must be signed in to change notification settings - Fork 6.8k
perf(tooltip): Defer hooking up events until there's a message and the tooltip is not disabled #19764
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
perf(tooltip): Defer hooking up events until there's a message and the tooltip is not disabled #19764
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -144,6 +144,7 @@ export class MatTooltip implements OnDestroy, AfterViewInit { | |
private _disabled: boolean = false; | ||
private _tooltipClass: string|string[]|Set<string>|{[key: string]: any}; | ||
private _scrollStrategy: () => ScrollStrategy; | ||
private _viewInitialized = false; | ||
|
||
/** Allows the user to define the position of the tooltip relative to the parent element */ | ||
@Input('matTooltipPosition') | ||
|
@@ -173,6 +174,8 @@ export class MatTooltip implements OnDestroy, AfterViewInit { | |
// If tooltip is disabled, hide immediately. | ||
if (this._disabled) { | ||
this.hide(0); | ||
} else { | ||
this._setupPointerEvents(); | ||
} | ||
} | ||
|
||
|
@@ -202,14 +205,17 @@ export class MatTooltip implements OnDestroy, AfterViewInit { | |
@Input('matTooltip') | ||
get message() { return this._message; } | ||
set message(value: string) { | ||
this._ariaDescriber.removeDescription(this._elementRef.nativeElement, this._message); | ||
if (this._message) { | ||
this._ariaDescriber.removeDescription(this._elementRef.nativeElement, this._message); | ||
} | ||
|
||
// If the message is not a string (e.g. number), convert it to a string and trim it. | ||
this._message = value != null ? `${value}`.trim() : ''; | ||
|
||
if (!this._message && this._isTooltipVisible()) { | ||
this.hide(0); | ||
} else { | ||
this._setupPointerEvents(); | ||
this._updateTooltipMessage(); | ||
this._ngZone.runOutsideAngular(() => { | ||
// The `AriaDescriber` has some functionality that avoids adding a description if it's the | ||
|
@@ -276,6 +282,7 @@ export class MatTooltip implements OnDestroy, AfterViewInit { | |
|
||
ngAfterViewInit() { | ||
// This needs to happen after view init so the initial values for all inputs have been set. | ||
this._viewInitialized = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the only case where this would help is if the message changes quickly before There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better to be safe, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO it's overly-protective since people would have to actively go out of their way to make it behave differently, and even if it does, it won't actually break, it'll just bind some events before they're actually needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was there a reason that it hooked up in ngAfterViewInit before? My concern was that adding the call to the message and disabled setters would cause the events to be attached earlier than they were before without this check. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think there's a specific reason for it. My guess is that we had the lifecycle hook defined already so we reused it instead of adding another one. |
||
this._setupPointerEvents(); | ||
|
||
this._focusMonitor.monitor(this._elementRef) | ||
|
@@ -543,6 +550,12 @@ export class MatTooltip implements OnDestroy, AfterViewInit { | |
|
||
/** Binds the pointer events to the tooltip trigger. */ | ||
private _setupPointerEvents() { | ||
// Optimization: Defer hooking up events if there's no message or the tooltip is disabled. | ||
if (this._disabled || !this.message || !this._viewInitialized || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that this check should be at the call site, rather than inside There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's safer to be here - otherwise it could accidentally be omitted. Would adding a return boolean value here be ok for if the caller needs to know? Alternatively, they can just check this._passiveListeners.size There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a private API so we can probably get away with not returning what the result was. Let's keep it like this for now and we can rework it if it becomes an issue. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm fine with this behavior with the names in your follow-up PR |
||
this._passiveListeners.size) { | ||
return; | ||
} | ||
|
||
// The mouse events shouldn't be bound on mobile devices, because they can prevent the | ||
// first tap from firing its click event or can cause the tooltip to open for clicks. | ||
if (!this._platform.IOS && !this._platform.ANDROID) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than checking
message
here, couldAriaDescriber
just check this and no-op immediately?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updating in #19777