javascript - To open angular material tooltip above when the page is scrolled and avoid the tooltip getting hidden - Stack Overf

I have added 2 tables in stackblitz link, if I hover in first table(1st column) alst rows the tooltip o

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

.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-tipponent.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-tipponent.html",
 styleUrls: ["./custom-tool-tipponent.css"]
})
export class CustomToolTipComponent extends TooltipComponent {

 @Input() text: string;
 @Input() contentTemplate: TemplateRef<any>;

}

custom-tool-tipponent.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 plete
  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);
}
}

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./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.ponent.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.ponent.html",
 styleUrls: ["./custom-tool-tip.ponent.css"]
})
export class CustomToolTipComponent extends TooltipComponent {

 @Input() text: string;
 @Input() contentTemplate: TemplateRef<any>;

}

custom-tool-tip.ponent.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 plete
  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);
}
}
Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Apr 13, 2020 at 16:10 EnthuEnthu 5322 gold badges15 silver badges42 bronze badges 3
  • where is stackblitz link? – Gourav Garg Commented Apr 14, 2020 at 17:05
  • @GouravGarg, my bad missed it , have added now, thanks – Enthu Commented Apr 14, 2020 at 20:07
  • Can you update your project to angular 7? – Gourav Garg Commented Apr 15, 2020 at 7:08
Add a ment  | 

2 Answers 2

Reset to default 3

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 ponent 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

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

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745298099a4621265.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信