问题
I have added 2 tables in stackblitz link, if I hover in first table(1st column) alst rows the tooltip opens above(expected) but when we scroll down the page and then hover on the last rows of 2nd table, the tooltip gets hidden in the bottom of the screen, as was not the case if I have a single table. I was expecting the tooltip to be opened above instead of getting hidden in the bottom. Please suggest.
Stacblitz link
https://stackblitz.com/edit/angular-mat-tooltip-ctvigc?file=app%2Ftooltip-overview-example.html
tooltip-overview-example.html
<ng-container matColumnDef="Column1">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Alert </th>
<td mat-cell *matCellDef="let row; let i = index" customToolTip [contentTemplate]="template">
<span >{{row.Column1}}</span>
<!--TOOLTIP-->
<ng-template #template>
<div style="display: flex; flex-direction: column">
<span>{{row.conditionals | json}}</span>
<button (click)="onClick(i)">Click</button>
</div>
</ng-template>
</td>
</ng-container>
Extended the Angular material TooltipComponent in CustomToolTipComponent
custom-tool-tip.component.ts
import {
Component,
OnInit,
OnDestroy,
Input,
TemplateRef
} from "@angular/core";
import {TooltipComponent} from "@angular/material/tooltip"
import { Observable, Subject } from "rxjs";
@Component({
selector: "app-custom-tool-tip",
templateUrl: "./custom-tool-tip.component.html",
styleUrls: ["./custom-tool-tip.component.css"]
})
export class CustomToolTipComponent extends TooltipComponent {
@Input() text: string;
@Input() contentTemplate: TemplateRef<any>;
}
custom-tool-tip.component.html
<div>
<div class="tooltip-conatiner">
<ng-template #simpleText>
{{text}}
</ng-template>
<ng-container *ngTemplateOutlet="contentTemplate || simpleText">
</ng-container>
</div>
</div>
tool-tip-renderer.directive.ts
@Directive({
selector: "[customToolTip]"
})
export class ToolTipRendererDirective {
@Input() showToolTip: boolean = true;
//If this is specified then specified text will be showin in the tooltip
@Input(`customToolTip`) text: string;
//If this is specified then specified template will be rendered in the tooltip
@Input() contentTemplate: TemplateRef<any>;
private _overlayRef: OverlayRef;
private _tooltipInstance;
private _mouseInTooltip: boolean = false;
private _hasListeners: boolean = false;
constructor(
private _overlay: Overlay,
private _overlayPositionBuilder: OverlayPositionBuilder,
private _elementRef: ElementRef,
private _r2: Renderer2
) {}
ngOnInit() {
if (!this.showToolTip) {
return;
}
const positionStrategy = this._overlayPositionBuilder
.flexibleConnectedTo(this._elementRef)
.withPositions([
{
originX: "center",
originY: "bottom",
overlayX: "center",
overlayY: "top",
offsetY: -10
}
]);
this._overlayRef = this._overlay.create({ positionStrategy });
}
@HostListener("mouseenter")
show(e) {
if (this._overlayRef && !this._overlayRef.hasAttached()) {
//set tooltip instance
this._tooltipInstance = this._overlayRef.attach(
new ComponentPortal(CustomToolTipComponent)
).instance;
//set CustomToolTipComponenet content/inputs
this._tooltipInstance.text = this.text;
this._tooltipInstance.contentTemplate = this.contentTemplate;
//render tooltip
this._tooltipInstance!.show(0);
//sub to detach after hide anitmation is complete
this._tooltipInstance
.afterHidden()
.pipe(take(1))
.subscribe(() => {
this._overlayRef.detach();
});
if (!this._hasListeners) {
this._hasListeners = true;
//attach mouseleave listener to detach when mouseleave on tooltip
this._r2.listen(this._overlayRef.overlayElement, "mouseleave", () => {
//call hide function in this directive
this._mouseInTooltip = false;
this.hide();
});
this._r2.listen(this._overlayRef.overlayElement, "mouseenter", () => {
//call hide function in this directive
this._mouseInTooltip = true;
});
}
}
}
@HostListener("mouseleave")
hide(buttonClicked = null) {
if(buttonClicked)
this._mouseInTooltip = false;
setTimeout(() => {
if (!this._mouseInTooltip) this._tooltipInstance!._onHide.next();
}, 20);
}
}
回答1:
To fix this, you need to upgrade your cdk version to 7.3.7 which has a new method on OverlayRef as updatePositionStrategy.
According to this method you can change the position strategy of an overlay after attach.
In your show function after attaching the component you need to update position strategy as below:
this._overlayRef.updatePositionStrategy(this._overlayPositionBuilder
.flexibleConnectedTo(this._elementRef)
.withPositions([{
originX: "center",
originY: "bottom",
overlayX: "center",
overlayY: "top",
offsetY: this.getOffsetY()
}]));
this._overlayRef.updatePosition();
where this.getOffsetY() is private method provide offset y value based on element current position. You may need to update this logic.
private getOffsetY() {
if (this._elementRef.nativeElement.getBoundingClientRect().bottom > 500)
return -400;
if (this._elementRef.nativeElement.getBoundingClientRect().bottom > 400)
return -300;
if (this._elementRef.nativeElement.getBoundingClientRect().bottom > 300)
return -200;
return -10;
}
Here is stackblitz link
回答2:
You can get the event.screenX and Event event.screenY position and using that check the height of the screen by getting screen height and screen width .
screen.height
Then check if the event is not near to the screen height if then make the [matTooltipPosition]="position.value"
to be above..
Like this you have to check
来源:https://stackoverflow.com/questions/61191974/to-open-angular-material-tooltip-above-when-the-page-is-scrolled-and-avoid-the-t