Skip to content

Commit

Permalink
feat(popup): pass context to popup open method
Browse files Browse the repository at this point in the history
Closes #1145
  • Loading branch information
isaacplmann authored and pkozlowski-opensource committed Dec 21, 2016
1 parent 4554855 commit 87d569b
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 9 deletions.
6 changes: 6 additions & 0 deletions demo/src/app/components/popover/demos/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {NgbdPopoverBasic} from './basic/popover-basic';
import {NgbdPopoverTplcontent} from './tplcontent/popover-tplcontent';
import {NgbdPopoverTplwithcontext} from './tplwithcontext/popover-tplwithcontext';
import {NgbdPopoverTriggers} from './triggers/popover-triggers';
import {NgbdPopoverVisibility} from './visibility/popover-visibility';
import {NgbdPopoverContainer} from './container/popover-container';
Expand All @@ -8,6 +9,7 @@ import {NgbdPopoverConfig} from './config/popover-config';
export const DEMO_DIRECTIVES = [
NgbdPopoverBasic,
NgbdPopoverTplcontent,
NgbdPopoverTplwithcontext,
NgbdPopoverTriggers,
NgbdPopoverVisibility,
NgbdPopoverContainer,
Expand All @@ -27,6 +29,10 @@ export const DEMO_SNIPPETS = {
code: require('!!prismjs-loader?lang=typescript!./triggers/popover-triggers'),
markup: require('!!prismjs-loader?lang=markup!./triggers/popover-triggers.html')
},
tplwithcontext: {
code: require('!!prismjs-loader?lang=typescript!./tplwithcontext/popover-tplwithcontext'),
markup: require('!!prismjs-loader?lang=markup!./tplwithcontext/popover-tplwithcontext.html')
},
visibility: {
code: require('!!prismjs-loader?lang=typescript!./visibility/popover-visibility'),
markup: require('!!prismjs-loader?lang=markup!./visibility/popover-visibility.html')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<p>
You can optionally pass in a context when manually triggering a popover.
</p>

<template #popContent let-greeting="greeting">{{greeting}}, <b>{{name}}</b>!</template>
<p>
How would you like to greet <strong [ngbPopover]="popContent" popoverTitle="Greeting" #p="ngbPopover" triggers="manual">me</strong>?
</p>
<button type="button" class="btn btn-secondary" (click)="changeGreeting({ greeting: 'Bonjour' })">
French
</button>
<button type="button" class="btn btn-secondary" (click)="changeGreeting({ greeting: 'Gutentag' })">
German
</button>
<button type="button" class="btn btn-secondary" (click)="changeGreeting({ greeting: 'Hello' })">
English
</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {NgbPopover} from '@ng-bootstrap/ng-bootstrap';
import {Component, ViewChild} from '@angular/core';

@Component({
selector: 'ngbd-popover-tplwithcontext',
templateUrl: './popover-tplwithcontext.html'
})
export class NgbdPopoverTplwithcontext {
greeting = {};
name = 'World';

@ViewChild('p') public popover: NgbPopover;

public changeGreeting(greeting: any): void {
const isOpen = this.popover.isOpen();
this.popover.close();
if (greeting !== this.greeting || !isOpen) {
this.greeting = greeting;
this.popover.open(greeting);
}
}
}
4 changes: 4 additions & 0 deletions demo/src/app/components/popover/popover.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import {DEMO_SNIPPETS} from './demos';
demoTitle="Custom and manual triggers" [snippets]="snippets" component="popover" demo="triggers">
<ngbd-popover-triggers></ngbd-popover-triggers>
</ngbd-example-box>
<ngbd-example-box
demoTitle="Context and manual triggers" [snippets]="snippets" component="popover" demo="tplwithcontext">
<ngbd-popover-tplwithcontext></ngbd-popover-tplwithcontext>
</ngbd-example-box>
<ngbd-example-box
demoTitle="Popover visibility events" [snippets]="snippets" component="popover" demo="visibility">
<ngbd-popover-visibility></ngbd-popover-visibility>
Expand Down
14 changes: 13 additions & 1 deletion demo/src/app/components/tooltip/demos/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import {NgbdTooltipBasic} from './basic/tooltip-basic';
import {NgbdTooltipContainer} from './container/tooltip-container';
import {NgbdTooltipTplcontent} from './tplcontent/tooltip-tplcontent';
import {NgbdTooltipTplwithcontext} from './tplwithcontext/tooltip-tplwithcontext';
import {NgbdTooltipTriggers} from './triggers/tooltip-triggers';
import {NgbdTooltipConfig} from './config/tooltip-config';

export const DEMO_DIRECTIVES = [NgbdTooltipBasic, NgbdTooltipContainer, NgbdTooltipTplcontent, NgbdTooltipTriggers, NgbdTooltipConfig];
export const DEMO_DIRECTIVES = [
NgbdTooltipBasic,
NgbdTooltipContainer,
NgbdTooltipTplcontent,
NgbdTooltipTriggers,
NgbdTooltipConfig,
NgbdTooltipTplwithcontext
];

export const DEMO_SNIPPETS = {
basic: {
Expand All @@ -23,6 +31,10 @@ export const DEMO_SNIPPETS = {
code: require('!!prismjs-loader?lang=typescript!./triggers/tooltip-triggers'),
markup: require('!!prismjs-loader?lang=markup!./triggers/tooltip-triggers.html')
},
tplwithcontext: {
code: require('!!prismjs-loader?lang=typescript!./tplwithcontext/tooltip-tplwithcontext'),
markup: require('!!prismjs-loader?lang=markup!./tplwithcontext/tooltip-tplwithcontext.html')
},
config: {
code: require('!!prismjs-loader?lang=typescript!./config/tooltip-config'),
markup: require('!!prismjs-loader?lang=markup!./config/tooltip-config.html')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<p>
You can optionally pass in a context when manually triggering a popover.
</p>

<template #tipContent let-greeting="greeting">{{greeting}}, <b>{{name}}</b>!</template>
<p>
How would you like to greet <strong [ngbTooltip]="tipContent" #t="ngbTooltip" triggers="manual">me</strong>?
</p>
<button type="button" class="btn btn-secondary" (click)="changeGreeting({ greeting: 'Bonjour' })">
French
</button>
<button type="button" class="btn btn-secondary" (click)="changeGreeting({ greeting: 'Gutentag' })">
German
</button>
<button type="button" class="btn btn-secondary" (click)="changeGreeting({ greeting: 'Hello' })">
English
</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {NgbTooltip} from '@ng-bootstrap/ng-bootstrap';
import {Component, ViewChild} from '@angular/core';

@Component({
selector: 'ngbd-tooltip-tplwithcontext',
templateUrl: './tooltip-tplwithcontext.html'
})
export class NgbdTooltipTplwithcontext {
greeting = {};
name = 'World';

@ViewChild('t') public tooltip: NgbTooltip;

public changeGreeting(greeting: any): void {
const isOpen = this.tooltip.isOpen();
this.tooltip.close();
if (greeting !== this.greeting || !isOpen) {
this.greeting = greeting;
this.tooltip.open(greeting);
}
}
}
4 changes: 4 additions & 0 deletions demo/src/app/components/tooltip/tooltip.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import {DEMO_SNIPPETS} from './demos';
demoTitle="Custom and manual triggers" [snippets]="snippets" component="tooltip" demo="triggers">
<ngbd-tooltip-triggers></ngbd-tooltip-triggers>
</ngbd-example-box>
<ngbd-example-box
demoTitle="Context and manual triggers" [snippets]="snippets" component="tooltip" demo="tplwithcontext">
<ngbd-tooltip-tplwithcontext></ngbd-tooltip-tplwithcontext>
</ngbd-example-box>
<ngbd-example-box
demoTitle="Append tooltip in the body" [snippets]="snippets" component="tooltip" demo="container">
<ngbd-tooltip-container></ngbd-tooltip-container>
Expand Down
22 changes: 22 additions & 0 deletions src/popover/popover.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,28 @@ describe('ngb-popover', () => {
expect(getWindow(fixture.nativeElement)).toBeNull();
});

it('should open and close a popover - default settings, content from a template and context supplied', () => {
const fixture = createTestComponent(`
<template #t let-name="name">Hello, {{name}}!</template>
<div [ngbPopover]="t" popoverTitle="Title"></div>`);
const directive = fixture.debugElement.query(By.directive(NgbPopover));
const defaultConfig = new NgbPopoverConfig();

directive.context.popover.open({name: 'John'});
fixture.detectChanges();
const windowEl = getWindow(fixture.nativeElement);

expect(windowEl).toHaveCssClass('popover');
expect(windowEl).toHaveCssClass(`popover-${defaultConfig.placement}`);
expect(windowEl.textContent.trim()).toBe('TitleHello, John!');
expect(windowEl.getAttribute('role')).toBe('tooltip');
expect(windowEl.parentNode).toBe(fixture.nativeElement);

directive.triggerEventHandler('click', {});
fixture.detectChanges();
expect(getWindow(fixture.nativeElement)).toBeNull();
});

it('should properly destroy TemplateRef content', () => {
const fixture = createTestComponent(`
<template #t><destroyable-cmpt></destroyable-cmpt></template>
Expand Down
5 changes: 3 additions & 2 deletions src/popover/popover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,11 @@ export class NgbPopover implements OnInit, OnDestroy {

/**
* Opens an element’s popover. This is considered a “manual” triggering of the popover.
* The context is an optional value to be injected into the popover template when it is created.
*/
open() {
open(context?: any) {
if (!this._windowRef) {
this._windowRef = this._popupService.open(this.ngbPopover);
this._windowRef = this._popupService.open(this.ngbPopover, context);
this._windowRef.instance.placement = this.placement;
this._windowRef.instance.title = this.popoverTitle;

Expand Down
19 changes: 19 additions & 0 deletions src/tooltip/tooltip.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,25 @@ describe('ngb-tooltip', () => {
expect(getWindow(fixture.nativeElement)).toBeNull();
});

it('should open and close a tooltip - default settings, content from a template and context supplied', () => {
const fixture = createTestComponent(`<template #t let-name="name">Hello, {{name}}!</template><div [ngbTooltip]="t"></div>`);
const directive = fixture.debugElement.query(By.directive(NgbTooltip));

directive.context.tooltip.open({name: 'John'});
fixture.detectChanges();
const windowEl = getWindow(fixture.nativeElement);

expect(windowEl).toHaveCssClass('tooltip');
expect(windowEl).toHaveCssClass('tooltip-top');
expect(windowEl.textContent.trim()).toBe('Hello, John!');
expect(windowEl.getAttribute('role')).toBe('tooltip');
expect(windowEl.parentNode).toBe(fixture.nativeElement);

directive.triggerEventHandler('mouseleave', {});
fixture.detectChanges();
expect(getWindow(fixture.nativeElement)).toBeNull();
});

it('should not open a tooltip if content is falsy', () => {
const fixture = createTestComponent(`<div [ngbTooltip]="notExisting"></div>`);
const directive = fixture.debugElement.query(By.directive(NgbTooltip));
Expand Down
5 changes: 3 additions & 2 deletions src/tooltip/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@ export class NgbTooltip implements OnInit, OnDestroy {

/**
* Opens an element’s tooltip. This is considered a “manual” triggering of the tooltip.
* The context is an optional value to be injected into the tooltip template when it is created.
*/
open() {
open(context?: any) {
if (!this._windowRef && this._ngbTooltip) {
this._windowRef = this._popupService.open(this._ngbTooltip);
this._windowRef = this._popupService.open(this._ngbTooltip, context);
this._windowRef.instance.placement = this.placement;

if (this.container === 'body') {
Expand Down
8 changes: 4 additions & 4 deletions src/util/popup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export class PopupService<T> {
this._windowFactory = componentFactoryResolver.resolveComponentFactory<T>(type);
}

open(content?: string | TemplateRef<any>): ComponentRef<T> {
open(content?: string | TemplateRef<any>, context?: any): ComponentRef<T> {
if (!this._windowRef) {
this._contentRef = this._getContentRef(content);
this._contentRef = this._getContentRef(content, context);
this._windowRef =
this._viewContainerRef.createComponent(this._windowFactory, 0, this._injector, this._contentRef.nodes);
}
Expand All @@ -46,11 +46,11 @@ export class PopupService<T> {
}
}

private _getContentRef(content: string | TemplateRef<any>): ContentRef {
private _getContentRef(content: string | TemplateRef<any>, context?: any): ContentRef {
if (!content) {
return new ContentRef([]);
} else if (content instanceof TemplateRef) {
const viewRef = this._viewContainerRef.createEmbeddedView(<TemplateRef<T>>content);
const viewRef = this._viewContainerRef.createEmbeddedView(<TemplateRef<T>>content, context);
return new ContentRef([viewRef.rootNodes], viewRef);
} else {
return new ContentRef([[this._renderer.createText(null, `${content}`)]]);
Expand Down

0 comments on commit 87d569b

Please sign in to comment.