Popover/tooltip mouseleave trigger - extend mouseleave area to tooltip/popover content
Bug description or feature request:
When using Tooltip/Popover component, we can specify custom triggers when they will appear/hide. What I am trying to achieve is to display tooltip/popover on hover and hide when either popover element or popover content are not hovering. Currently, it only works for the element on which popover is attached, but if we have some links or something in the popover content, we will not be able to click them.
Is there an option to include also popover content for "mouseleave" trigger when closing/hiding element?
Plunker/StackBlitz that reproduces the issue:
https://stackblitz.com/edit/angular-jcy2ks?file=src%2Fapp%2Fapp.component.html
Versions of ngx-bootstrap, Angular, and Bootstrap:
ngx-bootstrap: 5.1.1
Angular: 8.0.0
Bootstrap: 4.3.1
Build system: Angular CLI, System.js, webpack, starter seed:
5 years later, still no answer... What a shame...
Posting this in case someone else needs a quick workaround. Unfortunately, I had to override PopoverDirective instead of extending it since one of the dependencies is not exported ComponentLoaderFactory:
import { ElementRef } from '@angular/core';
import { PopoverDirective } from 'ngx-bootstrap/popover';
export const overridePopoverWithHover = () => {
const proShow = PopoverDirective.prototype.show
const proHide = PopoverDirective.prototype.hide
const proOnDestroy = PopoverDirective.prototype.ngOnDestroy
const hoverMap = new Map<string, boolean>()
const getHandlers = (ref: ElementRef, hide: () => void, delay: number) => {
if (!hoverMap.has(ref.nativeElement.id)) hoverMap.set(ref.nativeElement.id, false)
return {
isHovering: () => !!hoverMap.get(ref.nativeElement.id),
enter: {
event: 'mouseenter',
handler: () => hoverMap.set(ref.nativeElement.id, true),
},
leave: {
event: 'mouseleave',
handler: () => {
hoverMap.set(ref.nativeElement.id, false)
setTimeout(() => hide(), delay)
},
},
}
}
PopoverDirective.prototype.show = function () {
proShow.call(this)
const handlers = getHandlers(this['_elementRef'], this.hide.bind(this), this.delay)
const el = this['_popover']?._componentRef?.location?.nativeElement
el?.addEventListener(handlers.enter.event, handlers.enter.handler)
el?.addEventListener(handlers.leave.event, handlers.leave.handler)
}
PopoverDirective.prototype.hide = function () {
setTimeout(() => {
const handlers = getHandlers(this['_elementRef'], this.hide.bind(this), this.delay)
const el = this['_popover']?._componentRef?.location?.nativeElement
if (handlers.isHovering()) return
el?.removeEventListener(handlers.enter.event, handlers.enter.handler)
el?.removeEventListener(handlers.leave.event, handlers.leave.handler)
proHide.call(this)
}, this.delay)
}
PopoverDirective.prototype.ngOnDestroy = function () {
const handlers = getHandlers(this['_elementRef'], this.hide.bind(this), this.delay)
const el = this['_popover']?._componentRef?.location?.nativeElement
el?.removeEventListener(handlers.enter.event, handlers.enter.handler)
el?.removeEventListener(handlers.leave.event, handlers.leave.handler)
proOnDestroy.call(this)
}
}