angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.39k stars 6.76k forks source link

tooltip: buggy when deployed as an Angular Element #15781

Open turbolego opened 5 years ago

turbolego commented 5 years ago

What is the expected behavior?

That tooltips are not buggy.

What is the current behavior?

Tooltips are buggy.

What are the steps to reproduce?

app.module.ts import { MatTooltipModule } from '@angular/material/tooltip';

somecomponent.component.html <button mat-button class="button" (click)="openDialog()" matTooltip="Åpne" aria-label="Åpne"> ÅPNE</button>

And then deploy the whole project as an Angular Element.

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Angular CLI: 7.3.6 Node: 10.15.2 OS: win32 x64 Angular: 7.2.10 @angular/material 7.3.5 typescript 3.1.1 Chrome Version 73.0.3683.86 (Official Build) (64-bit)

Is there anything else we should know?

Every time i hover on the button, a small grey "blob" is added to a "row" under the address-field in my browser.

Screenshot_188

When i click the button, a "tick()" is triggered (because angular elements needs that without ngZone) and the row of grey blobs is replaced with the tooltip. It's in the wrong spot, but it's there. I suspect this has something to do with how "Angular Elements" work? Since the grey blobs were only "converted" to the tooltip after a "tick()"?

Screenshot_189

@levgaas posted the same issue a year ago, but did not specify how he managed to fix it: https://github.com/angular/material2/issues/11361

turbolego commented 5 years ago

Just in case anyone else has problems with this, we ended up "hiding" the original tooltips in the paginator and adding our own using "pure css". It's not pretty, but it works while this gets sorted out.

in styles.scss (to hide the existing tooltip):

mat-tooltip-component > .mat-tooltip { display: none; }

Added the following code to the .scss file of the component where we have the paginator: (Stole some code from this guide by @yjose: https://medium.freecodecamp.org/a-step-by-step-guide-to-making-pure-css-tooltips-3d5a3e237346)


:root {
  --paginator-next-button: "Next Page";
  --paginator-previous-button: "Previous Page";
}

.mat-paginator-navigation-next::after {
  content: var(--paginator-next-button);
}
.mat-paginator-navigation-previous::after {
  content: var(--paginator-previous-button);
}

.mat-paginator-navigation-next:hover::after,
.mat-paginator-navigation-next:hover::before,
.mat-paginator-navigation-previous:hover::after,
.mat-paginator-navigation-previous:hover::before {
  opacity:1;
  transition:opacity  0s linear 1s;
}

.mat-paginator-navigation-next,.mat-paginator-navigation-previous {
  position:relative;
  display:inline-block;
}

.mat-paginator-navigation-next::before,.mat-paginator-navigation-previous::before{
  position: absolute;
  bottom: -35px;
  left: 50%;
  padding: 8px;
  transform: translateX(-50%) scale(0);
  transition: transform 0.3s ease-in-out;
  transform-origin: top;
  background: #616161e6;
  color: white;
  border-radius: 2px;
  font-size: 12px;
  font-family: Roboto,sans-serif;
  font-weight: 400;

}

.mat-paginator-navigation-next::after,.mat-paginator-navigation-previous::after{
  position: absolute;
  left:50%;
  top:-6px;
  transform: translateX(-50%)   translateY(-100%);
  background: #616161e6;
  color: white;
  text-align: center;
  line-height: 1.5;
  padding:4px 2px;
  font-size: 12px;
  min-width: 80px;
  border-radius: 5px;
  pointer-events: none;
  padding: 4px 4px;
  z-index:99;
  opacity:0;
}
Varuna15 commented 5 years ago

Even i am facing the same issue in my project. Do we have solution or a fix for getting around this issue?

Splaktar commented 5 years ago

Can you please post a StackBlitz reproduction?

turbolego commented 5 years ago

This is also happening with mat-option drop downs... they "expand" in the top left corner in my Angular Elements 😶 Is it common for stuff to end up in the top left corner if you deploy as Angular element?

Splaktar commented 5 years ago

@turbolego there are a number of open issues related to Angular Elements. There is no official demo or testing of Angular Material with Angular Elements at this time. We only do some basic testing with Angular Elements in the dev-app. So there's currently no canonical example to compare against.

Please provide a GitHub repo and/or StackBlitz that reproduces this issue so that it can be investigated.

noonhe commented 5 years ago

I'm facing the same problem. I'm using Angular/cli 8.2.2 , angular/material 8.1.3 I have a mat-accordion that has two mat-expansion-panels and in both of them there's mat-tab-groups and in each tab there's an ag-grid. each ag-grid has a column with a custom cell renderer component that includes a set of mat-icon-buttons and each button has a matTooltip value. it works fine in all ag-grids of the fisrt mat-expansion-panel. and for the second mat-expansion-panel the ag-grid in the first mat-tab shows matTooltips fine. but rest of the tabs have this problem in displaying matTooltip values. I think the problem is with mat-tab because when I put those grids outside of the mat-tab-group it shows the tooltip. I'm sorry I can't share my code here. is there any solution?

Splaktar commented 5 years ago

@noonhe are you able to create a StackBlitz or GitHub reproduction so that we can start investigating and debugging this? Otherwise, it's most likely just going to continue to sit in this same state.

noonhe commented 5 years ago

I created a simple example similar to what I'm doing at my real project. it's still has that problem when I hover on the edit button in ag-grid. here's the stackblitz code: https://stackblitz.com/github/noonhe/material-tooltip-example I don't know if the problems is with tooltip or tabs because when I bring grids out of tabs they can show tooltips.

turbolego commented 5 years ago

I created a simple example similar to what I'm doing at my real project. it's still has that problem when I hover on the edit button in ag-grid. here's the stackblitz code: https://stackblitz.com/github/nbwiyrjar I don't know if the problems is with tooltip or tabs because when I bring grids out of tabs they can show tooltips.

Is the link broken or is it just me? 😶

noonhe commented 5 years ago

sorry. I fixed it.

turbolego commented 5 years ago

sorry. I fixed it.

For me stackblitz just says "Starting dev server" forever. Does it work for you?

noonhe commented 5 years ago

sorry. I fixed it.

For me stackblitz just says "Starting dev server" forever. Does it work for you?

I don't know what the problem is. in both stackblitz and codesandbox it gets stuck on "starting dev server" and "installing dependencies". but it works when I run it on my computer. can you please clone my repo and run it in your computer? https://github.com/noonhe/material-tooltip-example

Splaktar commented 5 years ago

Both StackBlitz links are not found for me. Thank you for posting the GitHub repo.

noonhe commented 5 years ago

I just found out if your grid has more than one pages, if you go to the second page there's no issue and it shows all tooltips correctly and even when you go back to the first page the issue is resolved and it works fine. the problem is only in the first page and until you don't change the page.!!! I hope this new information can be useful.

xigolle commented 4 years ago

Is there any progress/solution for this problem. We are also experiencing the same isue with the tooltips.

devtronic commented 4 years ago

I had the same problem. The reason why the tooltip is displayed buggy is because the change detection won't work properly in some cases. In my specific case *ngFor had broke the change detection.

I solved the problem by using this package: https://github.com/remackgeek/elements-zone-strategy

utkuferuz commented 4 years ago

I had the exact same problem in my project. I am using Angular Material in hybrid project where the Angular app bootstraps an AngularJS application. There were gray blobs on the buttons after key press or mouse click. I thought the problem was css at first because some legacy css exists in the AngularJS project but later we found out that some zone.js flags were disabled which affected the change detection cycle. Below is my updated code which works properly now.

(window as any).__Zone_disable_timers = false; (window as any).__Zone_disable_requestAnimationFrame = false; (window as any).__Zone_disable_XHR = false; (window as any).__Zone_disable_on_property = false;

EdTech101 commented 4 years ago

every time that you have to use a component with two or more structural directives nested (ngIf, ngFor) you have to utilize the ng-template component as a wrapper, the material design library uses that in some components, and that includes the tooltips, so in order to fix your issue you have to enclose whatever component that is being rendered "dynamically" inside an ng-template (mat-tabs, anything inside a ngFor directive, mat-tab-header, mat-tooltip, etc) , and conditionally make it visible with an ngIf directive depending on the type of material component you are using, some would need the *ngIf others simply don't

(note the *ngIf structural directive in the outermost component)

<ng-template *ngIf="condition">
    <table mat-table [dataSource]="sortedData">
        <ng-container *ngFor="let col of columns" [matColumnDef]="col.field">
            <th mat-header-cell *matHeaderCellDef> {{ col.title }} </th>
            <td mat-cell *matCellDef="let element">
                <div [ngSwitch]="col.type">
                    <div *ngSwitchCase="'date'">
                        <span matTooltipPosition="above" [matTooltip]="col.tooltip">
                            {{element[col.field] | date:'MM/dd/yyyy HH:mm'}}
                        </span>
                    </div>
                </div>
            </td>
        </ng-container>
    </table>
</ng-template>

(note that the ng-template tag doesn't have any structural directive)

<mat-tab-group>
    <mat-tab>
        <ng-template mat-tab-label>
            <label matTooltip="some text" matTooltipPosition="above">
                Label
            </label>
        </ng-template> 
    </mat-tab>
 </mat-tab-group>

https://blog.angular-university.io/angular-ng-template-ng-container-ngtemplateoutlet/

Depact commented 4 years ago

<ng-template *ngIf="condition">

But this construction is not supported by angular.

guntram commented 2 years ago

I am struggeling with these multiple empty matTooltips! It is not reliably reproducable in a simple environment with stackblitz.

In one simple component, I got an Input() boolean, which changes - it is referenced inside an *ngIf like that:

<div *ngIf="someBoolean">
  <div matTooltip="TEST">test</div>
</div>

When I remove the *ngIf, everything is working fine (no multiple empty tooltip overlay elements). I could not find a real solution, so to avoid using a different tooltip plugin, I use this to hide the empty tooltips:

.mat-tooltip:empty {
  display: none;
}

(This should be inside some global style-file, or ViewEncapsulation.none must be used.)

After setting the empty tooltips to hidden, I thought I needed to call changedetectorRef.detectChanges(), because the tooltip with the correct content will have a random delay before showing up:

<div *ngIf="someBoolean">
  <div matTooltip="TEST"
  (mouseover)="changeDetectorRef.detectChanges()"
  (mouseout)="changeDetectorRef.detectChanges()"
  [matTooltipShowDelay]="0"
  [matTooltipHideDelay]="0">test</div>
</div>

But none of these have any effect, the tooltip just shows after a random delay, and also disappears after a random delay.

What also has completely no effect, is using changeDetectorRef.detectChanges() or applicationRef.tick() after the someBoolean has been updated.

I must add that we are running on Angular11, because there were some limitations using Angular12+. We are running inside PremierePro (CEP-panel), and there were severe issues with the webpack version used by the Angular12+ setups :(

(If you are interested: check the Chromium Embedded Framework (CEF) section)

(Also, I have to say that using ng-template in any way (or the other suggestions in this thread or the other threads which adress this problem) did not solve it...)

guntram commented 2 years ago

Ok, I got it now :)

I guess I tried stuff with ngZone in the wrong place!

(We are using the eventBus module...)

constructor(private ngZone: NgZone) {}

this.eventBus.on<MetaData>(Events.STATUS).subscribe((metaData: MetaData) => {
  this.ngZone.run(() => {
    this.someBoolean= metaData.data.someBoolean;
  });
});
MartinJHammer commented 2 years ago

I experience this when downgrading an Angular component to AngularJS. My component works initially (dialog shows), but when an item is added to the list, the tooltip starts acting like described in this issue. Makes sense if it's related to change detection.

zivklara commented 2 years ago

I had a similar issue, caused by a function running out of ng zone. My tooltip issue was similar to the description here (little boxes usually on the top left corner, but not always on top, that disappeared once I hovered/clicked elsewhere...) my guess is that calling detectChanges() actually broke that even more.

In one of my components, I listened to mat autocomplete closed event, and when it was emitted, I ran a function that emits some value. Other components and services were emitting different outputs/functions/subjects due to that emit, and all were running out of ng zone. Eventually after some time I had these tooltip (and other change detection) issues in one of my other components.

The solution was to find the first function to run out of zone (in my case it was the function I ran when mat autocomplete closed event fired), and wrap its content with zone.run() (like mentioned by guntram in https://github.com/angular/components/issues/15781#issuecomment-1095045622) As a result, all other functions that ran by other components due to that event now run inside the ng zone and all works fine now.

html (listening to closed event): image

ts (wrapping with zone.run): image image

[in logs: "in ng zone: false"] image

Kamil-Fritz commented 1 year ago

The Issue is, that Angular Materials Overlay is using ngZone.onStable to update the position of its content. When using Angular Elements and setting ngZone to 'noop' this event never will be triggered and the position is not updated.

I solved the issue by overwriting the onStable EventEmitter in ngZone and emitting when a new subscriber is created:

image

This solves the problem with all Angular Material Components which use @angular/cdk Overlay, like MatToolTip and MatMenu.