components
components copied to clipboard
[Tooltip] Tooltip does not vanish after route navigation with reusable routes
Bug, feature request, or proposal:
Bug
What is the expected behavior?
A displayed tooltip should vanish, after navigating to a route with a different component.
What is the current behavior?
When a RouteReuseStrategy is implemented, then the tooltip doesn't vanish if the original route is detached while the tooltip was visible.
What are the steps to reproduce?
StackBlitz example: https://stackblitz.com/edit/angular-yvcjzp
A tooltip is displayed on button "Goto Page 2". Clicking on the button will navigate to page 2. This will causes the tooltip from page 1 to be stuck on the screen. It will only vanish once the user navigates back to page 1 again.
Disabling reusable routes by removing the custom RouteReuseStrategy will lead to the the expected behavior again:
providers: [
// remove this, and the tooltip starts to work properly
{ provide: RouteReuseStrategy, useClass: CustomReuseStrategy }
],
What is the use-case or motivation for changing an existing behavior?
Which versions of Angular, Material, OS, TypeScript, browsers are affected?
"dependencies": { "@angular/animations": "6.0.0", "@angular/cdk": "^6.0.0", "@angular/common": "6.0.0", "@angular/compiler": "6.0.0", "@angular/core": "6.0.0", "@angular/forms": "6.0.0", "@angular/http": "6.0.0", "@angular/material": "^6.0.0", "@angular/platform-browser": "6.0.0", "@angular/platform-browser-dynamic": "6.0.0", "@angular/router": "6.0.0", "core-js": "^2.4.1", "rxjs": "^6.1.0", "rxjs-compat": "^6.1.0", "zone.js": "^0.8.26" },
Is there anything else we should know?
we have the same issue.
"dependencies": { "@angular/animations": "^6.0.5", "@angular/cdk": "^6.3.0", "@angular/common": "^6.0.5", "@angular/compiler": "^6.0.5", "@angular/core": "^6.0.5", "@angular/flex-layout": "6.0.0-beta.16", "@angular/forms": "^6.0.5", "@angular/http": "^6.0.5", "@angular/material": "^6.3.0", "@angular/platform-browser": "^6.0.5", "@angular/platform-browser-dynamic": "^6.0.5", "@angular/router": "^6.0.5", "core-js": "^2.5.7", "ng-http-loader": "^2.3.0", "rxjs": "6.2.1", "upgrade-angular": "^0.1.3", "zone.js": "^0.8.19" },
Same issue, is it possible any workarounds for this issue?
I also have same issue. Posted in StackOverflow and sample in stackblitz
@Vizer Until this is fixed, I remove the tooltip manually with jquery from within the destination route component where the tooltip gets stuck:
public ngAfterViewInit() { $('mat-tooltip-component div:contains("Tooltiptext")').remove(); }
I know. Very ugly.
@nharrer Thanks for the work around.
I am not very sure it is right way do native. But it worked for me inside RouteReuseStrategy -> store method
while(document.getElementsByTagName('mat-tooltip-component').length > 0) { document.getElementsByTagName('mat-tooltip-component')[0].remove(); }
Workaround StackBlitz
@nharrer, thanks for message. I have came up with other solution using tooltip's methods. In my case it works like this:
- related template
<a class="action" [routerLink]="[itemId, 'details']">
<i class="material-icons" (click)="navigate($event)"
[matTooltip]="'Details'">assignment</i>
</a>
- related component code:
...
@ViewChild(MatTooltip)
tooltip: MatTooltip;
...
navigate(event: MouseEvent) {
event.stopPropagation();
event.stopImmediatePropagation(); // optional in my case
event.preventDefault(); // optional in my case
this.tooltip.hide();
setTimeout(() => {
this._router.navigate([this.itemId, 'details'], {
relativeTo: this._route
});
}, 50);
}
Hope this helps someone :)
Any update on this?
There's the problem also in nebular 5.0.
My current workaround:
Not a real solution but i made my own tooltip using like this. adjust margin-top for distance from item.
>component.html
<div class="myTooltip">
<span class="myTooltipText"> <!--Tooltip content --> </span>
...
</div>
>component.scss
.myTooltip {
position: relative;
display: inline-block;
}
.myTooltip .myTooltipText {
opacity: 0;
visibility: hidden;
font-size: 12px;
width: 400px;
pointer-events: none;
border: 1px solid;
padding: 0 15px;
background: #b2d3e4;
color: #00639e;
text-align: justify;
border-radius: 6px;
margin-top: -70px;
position: fixed;
z-index: 999;
overflow: visible;
min-height: 54px;
vertical-align: middle;
display: inline-flex;
transition: opacity .1s ease-in-out;
-webkit-transition: opacity .1s ease-in-out;
}
.myTooltip .myTooltipText::after {
content: " ";
left: 10%;
bottom: -10px;
overflow: visible;
font-size: 12px;
width: 12px;
color: #00639e;
z-index: 99999;
position: absolute;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #b2d3e4 transparent transparent transparent;
}
.myTooltip:hover .myTooltipText {
visibility: visible;
opacity: 1;
}
Another take on this one... On navigation start, detach the tooltip overlay. I tried to hide it via MatTooltip.hide()
but for some reason the tooltip just doesn't go away.
import {Directive, Injectable, OnDestroy, OnInit} from '@angular/core';
import {MatTooltip} from '@angular/material/tooltip';
import {NavigationStart, Router} from '@angular/router';
import {filter} from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class TooltipCollector {
collection = new Set<MatTooltip>();
constructor(router: Router) {
router.events.pipe(filter(e => e instanceof NavigationStart)).subscribe(() => {
for (let mt of this.collection) {
if (mt._tooltipInstance?.isVisible()) {
mt._overlayRef?.detach();
break;
}
}
});
}
}
@Directive({
selector: '[matTooltip]',
})
export class HideTooltipDirective implements OnInit, OnDestroy {
constructor(private mt: MatTooltip, private tc: TooltipCollector) {}
ngOnInit() {
this.tc.collection.add(this.mt);
}
ngOnDestroy() {
this.tc.collection.delete(this.mt);
}
}
Here is how I had to handle it for any overlays:
window.onpopstate = function(event) {
let overlay = document.getElementsByClassName('cdk-overlay-backdrop-showing')[0];
overlay && overlay.click();
};
or in the AppComponent
constructor(location: PlatformLocation) {
location.onPopState(() => {
let overlay = document.getElementsByClassName('cdk-overlay-backdrop-showing')[0] as HTMLElement;
overlay && overlay.click();
});
@setbro-prg Your solution doesn't work for me, cdk-overlay-backdrop-showing does not exists (Angular 13.2.5).
I found a solution using Router events to empty the overlay container on each NavigationStart event:
router.events.subscribe((event) => {
if (event instanceof NavigationStart) {
let overlay = document.getElementsByClassName('cdk-overlay-container')[0];
if (overlay) {
overlay.innerHTML = '';
}
}
});
I ran across this issue while debugging something similar related to matMenuTrigger, but my issue was calling an async function outside of the Angular zone.
What fixed it for me was running closeMenu() within NgZone.
constructor(...ngZone: NgZone) { ... }
hideFunction() {
setTimeout(() => { // or any async function that causes the issue
this.ngZone.run(() => this.matMenuTrigger.closeMenu()); // make sure it runs with ngZone
});
}
Without this, Angular was unaware that any changes had occured and wasn't removing the CDK overlay.