Skip to content

Commit

Permalink
feat(popover): allow specifying target for popover
Browse files Browse the repository at this point in the history
  • Loading branch information
jbarrus authored and maxokorokov committed Aug 25, 2022
1 parent 9c8bf98 commit 711bfd3
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<p>
You can choose a dynamic target with manual triggers. This is useful when adding tooltips
to dynamic html content.
</p>

<ng-template #popContent let-text="text" let-href="href"><a [attr.href]="href" target="_blank">open {{text}} in a new window</a></ng-template>

<p [ngbPopover]="popContent" autoClose="outside" triggers="manual" #paragraphElement>
Add tooltips to dynamic html that contains links like <a data-description="Angular Framework" href="https://angular.io">angular</a> or <a data-description="Angular Bootstrap Components" href="https://ng-bootstrap.github.io">ng-bootstrap</a>
</p>

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

import {NgbdPopoverTarget} from './popover-target';

@NgModule({
imports: [BrowserModule, NgbModule],
declarations: [NgbdPopoverTarget],
exports: [NgbdPopoverTarget],
bootstrap: [NgbdPopoverTarget]
})
export class NgbdPopoverTargetModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {Component, HostListener, ViewChild} from '@angular/core';
import {NgbPopover} from '@ng-bootstrap/ng-bootstrap';

@Component({
selector: 'ngbd-popover-target',
templateUrl: './popover-target.html'
})
export class NgbdPopoverTarget {
@ViewChild(NgbPopover, {static: false}) popover: NgbPopover;

@HostListener('mouseover', ['$event.target'])
onMouseOver(el: HTMLAnchorElement) {
if (el.dataset.description) {
if (this.popover.isOpen() && this.popover.target !== el) {
this.popover.close();
}
this.popover.target = el;
this.popover.open({text: el.dataset.description, href: el.href});
}
}
}
9 changes: 9 additions & 0 deletions demo/src/app/components/popover/popover.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import { NgbdPopoverTriggers } from './demos/triggers/popover-triggers';
import { NgbdPopoverTriggersModule } from './demos/triggers/popover-triggers.module';
import { NgbdPopoverVisibility } from './demos/visibility/popover-visibility';
import { NgbdPopoverVisibilityModule } from './demos/visibility/popover-visibility.module';
import { NgbdPopoverTarget} from './demos/custom-target/popover-target';
import { NgbdPopoverTargetModule } from './demos/custom-target/popover-target.module';
import { Routes } from '@angular/router';

const DEMOS = {
Expand Down Expand Up @@ -59,6 +61,12 @@ const DEMOS = {
code: require('!!raw-loader!./demos/tplwithcontext/popover-tplwithcontext').default,
markup: require('!!raw-loader!./demos/tplwithcontext/popover-tplwithcontext.html').default
},
target: {
title: 'Custom target',
type: NgbdPopoverTarget,
code: require('!!raw-loader!./demos/custom-target/popover-target').default,
markup: require('!!raw-loader!./demos/custom-target/popover-target.html').default
},
delay: {
title: 'Open and close delays',
type: NgbdPopoverDelay,
Expand Down Expand Up @@ -116,6 +124,7 @@ export const ROUTES: Routes = [
NgbdPopoverTriggersModule,
NgbdPopoverAutocloseModule,
NgbdPopoverVisibilityModule,
NgbdPopoverTargetModule,
NgbdPopoverContainerModule,
NgbdPopoverCustomClassModule,
NgbdPopoverDelayModule,
Expand Down
13 changes: 10 additions & 3 deletions src/popover/popover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ export class NgbPopover implements OnInit, OnDestroy, OnChanges {
*/
@Input() triggers: string;

/**
* Specifies the target element for the popover. If empty, uses host element.
* Only works with manual trigger.
*/
@Input() target: HTMLElement;

/**
* A selector specifying the element the popover should be appended to.
*
Expand Down Expand Up @@ -232,7 +238,8 @@ export class NgbPopover implements OnInit, OnDestroy, OnChanges {
this._windowRef.setInput('popoverClass', this.popoverClass);
this._windowRef.setInput('id', this._ngbPopoverWindowId);

this._renderer.setAttribute(this._elementRef.nativeElement, 'aria-describedby', this._ngbPopoverWindowId);
this._renderer.setAttribute(
this.target || this._elementRef.nativeElement, 'aria-describedby', this._ngbPopoverWindowId);

if (this.container === 'body') {
this._document.querySelector(this.container).appendChild(this._windowRef.location.nativeElement);
Expand All @@ -253,7 +260,7 @@ export class NgbPopover implements OnInit, OnDestroy, OnChanges {
// Setting up popper and scheduling updates when zone is stable
this._ngZone.runOutsideAngular(() => {
this._positioning.createPopper({
hostElement: this._elementRef.nativeElement,
hostElement: this.target || this._elementRef.nativeElement,
targetElement: this._windowRef !.location.nativeElement,
placement: this.placement,
appendToBody: this.container === 'body',
Expand Down Expand Up @@ -283,7 +290,7 @@ export class NgbPopover implements OnInit, OnDestroy, OnChanges {
*/
close(animation = this.animation) {
if (this._windowRef) {
this._renderer.removeAttribute(this._elementRef.nativeElement, 'aria-describedby');
this._renderer.removeAttribute(this.target || this._elementRef.nativeElement, 'aria-describedby');
this._popupService.close(animation).subscribe(() => {
this._windowRef = null;
this._positioning.destroy();
Expand Down

0 comments on commit 711bfd3

Please sign in to comment.