To open angular material tooltip above when the page is scrolled and avoid the tooltip getting hidden

倖福魔咒の 提交于 2020-05-09 06:49:10

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!