Skip to content

Commit c83188c

Browse files
authored
fix(popover): fix template context not being passed, update cdk to 7.2.1 (#1153)
Closes #1084 Closes #848
1 parent cb1c21e commit c83188c

File tree

9 files changed

+220
-378
lines changed

9 files changed

+220
-378
lines changed

package-lock.json

Lines changed: 190 additions & 199 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117
"@angular-devkit/build-angular": "0.10.2",
118118
"@angular-devkit/core": "7.0.2",
119119
"@angular-devkit/schematics": "7.0.2",
120-
"@angular/cdk": "7.0.0",
120+
"@angular/cdk": "7.2.1",
121121
"@angular/cli": "7.0.2",
122122
"@angular/compiler-cli": "7.0.0",
123123
"@angular/language-service": "7.0.0",
@@ -174,4 +174,4 @@
174174
"uglifyjs-webpack-plugin": "1.1.5"
175175
},
176176
"schematics": "./schematics/dist/collection.json"
177-
}
177+
}

scripts/gulp/tasks/bundle/rollup-config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const ROLLUP_GLOBALS = {
2121
'@angular/cdk/platform': 'ng.cdk.platform',
2222
'@angular/cdk/portal': 'ng.cdk.portal',
2323
'@angular/cdk/a11y': 'ng.cdk.a11y',
24-
'@angular/cdk/bidi': 'ng.cdk.bidi',
2524
'@angular/cdk/scrolling': 'ng.cdk.scrolling',
2625

2726

src/framework/theme/components/cdk/overlay/mapping.ts

Lines changed: 0 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
11
import {
2-
ApplicationRef,
3-
ComponentFactoryResolver,
4-
ComponentRef,
52
Directive,
6-
EmbeddedViewRef,
7-
Inject,
83
Injectable,
9-
Injector,
104
ModuleWithProviders,
115
NgModule,
12-
NgZone,
136
TemplateRef,
147
ViewContainerRef,
158
} from '@angular/core';
169
import {
1710
CdkPortal,
1811
CdkPortalOutlet,
1912
ComponentPortal,
20-
DomPortalOutlet,
2113
Portal,
2214
PortalInjector,
2315
PortalModule,
@@ -32,7 +24,6 @@ import {
3224
Overlay,
3325
OverlayConfig,
3426
OverlayContainer,
35-
OverlayKeyboardDispatcher,
3627
OverlayModule,
3728
OverlayPositionBuilder,
3829
OverlayRef,
@@ -41,9 +32,6 @@ import {
4132
ScrollStrategyOptions,
4233
} from '@angular/cdk/overlay';
4334
import { Platform } from '@angular/cdk/platform';
44-
import { Directionality } from '@angular/cdk/bidi';
45-
46-
import { NB_DOCUMENT } from '../../../theme.options';
4735

4836

4937
@Directive({ selector: '[nbPortal]' })
@@ -55,154 +43,10 @@ export class NbPortalOutletDirective extends CdkPortalOutlet {
5543
}
5644

5745
export class NbComponentPortal<T = any> extends ComponentPortal<T> {
58-
constructor(component: ComponentType<T>,
59-
vcr?: ViewContainerRef,
60-
injector?: Injector,
61-
public cfr?: ComponentFactoryResolver) {
62-
super(component, vcr, injector);
63-
}
64-
}
65-
66-
/**
67-
* TODO remove after @angular/cdk@7.0.0 relased
68-
* */
69-
export class NbDomPortalOutlet extends DomPortalOutlet {
70-
constructor(
71-
/** Element into which the content is projected. */
72-
public outletElement: Element,
73-
private componentFactoryResolver: ComponentFactoryResolver,
74-
private appRef: ApplicationRef,
75-
private defaultInjector: Injector) {
76-
super(outletElement, componentFactoryResolver, appRef, defaultInjector);
77-
}
78-
79-
/**
80-
* Attach the given ComponentPortal to DOM element using the ComponentFactoryResolver.
81-
* @param portal Portal to be attached
82-
* @returns Reference to the created component.
83-
*/
84-
attachComponentPortal<T>(portal: NbComponentPortal<T>): ComponentRef<T> {
85-
const resolver = portal.cfr || this.componentFactoryResolver;
86-
const componentFactory = resolver.resolveComponentFactory(portal.component);
87-
let componentRef: ComponentRef<T>;
88-
89-
// If the portal specifies a ViewContainerRef, we will use that as the attachment point
90-
// for the component (in terms of Angular's component tree, not rendering).
91-
// When the ViewContainerRef is missing, we use the factory to create the component directly
92-
// and then manually attach the view to the application.
93-
if (portal.viewContainerRef) {
94-
componentRef = portal.viewContainerRef.createComponent(
95-
componentFactory,
96-
portal.viewContainerRef.length,
97-
portal.injector || portal.viewContainerRef.parentInjector);
98-
99-
this.setDisposeFn(() => componentRef.destroy());
100-
} else {
101-
componentRef = componentFactory.create(portal.injector || this.defaultInjector);
102-
this.appRef.attachView(componentRef.hostView);
103-
this.setDisposeFn(() => {
104-
this.appRef.detachView(componentRef.hostView);
105-
componentRef.destroy();
106-
});
107-
}
108-
// At this point the component has been instantiated, so we move it to the location in the DOM
109-
// where we want it to be rendered.
110-
this.outletElement.appendChild(this.getComponentRootNode(componentRef));
111-
112-
return componentRef;
113-
}
114-
115-
/** Gets the root HTMLElement for an instantiated component. */
116-
private getComponentRootNode(componentRef: ComponentRef<any>): HTMLElement {
117-
return (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
118-
}
11946
}
12047

12148
@Injectable()
12249
export class NbOverlay extends Overlay {
123-
protected appRef: ApplicationRef;
124-
protected static nextUniqueId = 0;
125-
126-
constructor(
127-
/** Scrolling strategies that can be used when creating an overlay. */
128-
public scrollStrategies: ScrollStrategyOptions,
129-
protected overlayContainer: OverlayContainer,
130-
protected componentFactoryResolver: ComponentFactoryResolver,
131-
protected positionBuilder: OverlayPositionBuilder,
132-
protected keyboardDispatcher: OverlayKeyboardDispatcher,
133-
protected injector: Injector,
134-
protected ngZone: NgZone,
135-
@Inject(NB_DOCUMENT) private document: any,
136-
private directionality: Directionality) {
137-
super(
138-
scrollStrategies,
139-
overlayContainer,
140-
componentFactoryResolver,
141-
positionBuilder,
142-
keyboardDispatcher,
143-
injector,
144-
ngZone,
145-
document,
146-
directionality,
147-
);
148-
}
149-
150-
/**
151-
* Creates an overlay.
152-
* @param config Configuration applied to the overlay.
153-
* @returns Reference to the created overlay.
154-
*/
155-
create(config?: OverlayConfig): OverlayRef {
156-
const host = this.createHostElement();
157-
const pane = this.createPaneElement(host);
158-
const portalOutlet = this.createPortalOutlet(pane);
159-
const overlayConfig = new OverlayConfig(config);
160-
161-
overlayConfig.direction = overlayConfig.direction || this.directionality.value;
162-
163-
return new OverlayRef(portalOutlet, host, pane, overlayConfig, this.ngZone,
164-
this.keyboardDispatcher, this.document);
165-
}
166-
167-
/**
168-
* Creates the DOM element for an overlay and appends it to the overlay container.
169-
* @returns Newly-created pane element
170-
*/
171-
protected createPaneElement(host: HTMLElement): HTMLElement {
172-
const pane = this.document.createElement('div');
173-
174-
pane.id = `cdk-overlay-${NbOverlay.nextUniqueId++}`;
175-
pane.classList.add('cdk-overlay-pane');
176-
host.appendChild(pane);
177-
178-
return pane;
179-
}
180-
181-
/**
182-
* Creates the host element that wraps around an overlay
183-
* and can be used for advanced positioning.
184-
* @returns Newly-create host element.
185-
*/
186-
protected createHostElement(): HTMLElement {
187-
const host = this.document.createElement('div');
188-
this.overlayContainer.getContainerElement().appendChild(host);
189-
return host;
190-
}
191-
192-
/**
193-
* Create a DomPortalOutlet into which the overlay content can be loaded.
194-
* @param pane The DOM element to turn into a portal outlet.
195-
* @returns A portal outlet for the given DOM element.
196-
*/
197-
protected createPortalOutlet(pane: HTMLElement): NbDomPortalOutlet {
198-
// We have to resolve the ApplicationRef later in order to allow people
199-
// to use overlay-based providers during app initialization.
200-
if (!this.appRef) {
201-
this.appRef = this.injector.get<ApplicationRef>(ApplicationRef);
202-
}
203-
204-
return new NbDomPortalOutlet(pane, this.componentFactoryResolver, this.appRef, this.injector);
205-
}
20650
}
20751

20852
@Injectable()

src/framework/theme/components/cdk/overlay/overlay-container.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ import {
88
HostBinding,
99
Injector,
1010
Input,
11+
ViewChild,
1112
ViewContainerRef,
1213
} from '@angular/core';
1314

1415
import { NbPosition } from './overlay-position';
15-
import { NbComponentPortal, NbPortalInjector, NbTemplatePortal } from './mapping';
16+
import { NbComponentPortal, NbPortalInjector, NbPortalOutletDirective, NbTemplatePortal } from './mapping';
1617

1718
export abstract class NbPositionedContainer {
1819
@Input() position: NbPosition;
@@ -43,10 +44,13 @@ export abstract class NbPositionedContainer {
4344
selector: 'nb-overlay-container',
4445
template: `
4546
<div *ngIf="isStringContent" class="primitive-overlay">{{ content }}</div>
47+
<ng-template nbPortalOutlet></ng-template>
4648
`,
4749
changeDetection: ChangeDetectionStrategy.OnPush,
4850
})
4951
export class NbOverlayContainerComponent {
52+
@ViewChild(NbPortalOutletDirective) portalOutlet: NbPortalOutletDirective;
53+
5054
isAttached: boolean = false;
5155

5256
content: string;
@@ -61,17 +65,16 @@ export class NbOverlayContainerComponent {
6165
}
6266

6367
attachComponentPortal<T>(portal: NbComponentPortal<T>): ComponentRef<T> {
64-
const factory = portal.cfr.resolveComponentFactory(portal.component);
65-
const injector = this.createChildInjector(portal.cfr);
66-
const componentRef = this.vcr.createComponent(factory, null, injector);
68+
portal.injector = this.createChildInjector(portal.componentFactoryResolver);
69+
const componentRef = this.portalOutlet.attachComponentPortal(portal);
6770
this.isAttached = true;
6871
return componentRef;
6972
}
7073

7174
attachTemplatePortal<C>(portal: NbTemplatePortal<C>): EmbeddedViewRef<C> {
72-
const embeddedView = this.vcr.createEmbeddedView(portal.templateRef, portal.context);
73-
this.isAttached = true;
74-
return embeddedView;
75+
const templateRef = this.portalOutlet.attachTemplatePortal(portal);
76+
templateRef.detectChanges();
77+
return templateRef;
7578
}
7679

7780
attachStringContent(content: string) {

src/framework/theme/components/dialog/dialog.service.spec.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Component, NgModule } from '@angular/core';
2-
import { TestBed } from '@angular/core/testing';
2+
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
33

44
import { NbOverlayContainerAdapter, NbOverlayService, NbViewportRulerAdapter } from '../cdk';
55
import { NbDialogService } from './dialog.service';
@@ -126,28 +126,32 @@ describe('dialog-service', () => {
126126
expect(spy).toHaveBeenCalledTimes(0);
127127
});
128128

129-
it('should close on backdrop click if closeOnBackdropClick is true', () => {
129+
it('should close on backdrop click if closeOnBackdropClick is true', fakeAsync(() => {
130130
dialog.open(NbTestDialogComponent, { closeOnBackdropClick: true, autoFocus: false });
131131
queryBackdrop().dispatchEvent(new Event('click'));
132+
tick(500);
132133
expect(queryBackdrop()).toBeFalsy();
133-
});
134+
}));
134135

135-
it('should not close on backdrop click if closeOnBackdropClick is false', () => {
136+
it('should not close on backdrop click if closeOnBackdropClick is false', fakeAsync(() => {
136137
dialog.open(NbTestDialogComponent, { closeOnBackdropClick: false });
137138
queryBackdrop().dispatchEvent(new Event('click'));
139+
tick(500);
138140
expect(queryBackdrop()).toBeTruthy();
139-
});
141+
}));
140142

141-
it('should close on escape press if closeOnEsc is true', () => {
143+
it('should close on escape press if closeOnEsc is true', fakeAsync(() => {
142144
dialog.open(NbTestDialogComponent, { closeOnEsc: true });
143145
document.dispatchEvent(new KeyboardEvent('keyup', <any> { keyCode: 27 }));
146+
tick(500);
144147
expect(queryBackdrop()).toBeFalsy();
145-
});
148+
}));
146149

147-
it('should not close on escape press if closeOnEsc is false', () => {
150+
it('should not close on escape press if closeOnEsc is false', fakeAsync(() => {
148151
dialog.open(NbTestDialogComponent, { closeOnEsc: false });
149152
document.dispatchEvent(new KeyboardEvent('keyup', <any> { keyCode: 27 }));
153+
tick(500);
150154
expect(queryBackdrop()).toBeTruthy();
151-
});
155+
}));
152156
});
153157

src/framework/theme/components/popover/popover.component.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ export class NbPopoverComponent extends NbPositionedContainer implements AfterVi
4545
}
4646

4747
protected attachTemplate() {
48-
this.overlayContainer.attachTemplatePortal(new NbTemplatePortal(this.content, null, this.context));
48+
this.overlayContainer
49+
.attachTemplatePortal(new NbTemplatePortal(this.content, null, <any>{ $implicit: this.context }));
4950
}
5051

5152
protected attachComponent() {

src/framework/theme/components/popover/popover.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ describe('Directive: NbPopoverDirective', () => {
291291
expect(primitiveOverlay.textContent).toContain('test');
292292
});
293293

294-
xit('should provide context', () => {
294+
it('should provide context', () => {
295295
fixture.componentInstance.popover.show();
296296
fixture.detectChanges();
297297

src/framework/theme/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@
2828
"@angular/common": "^7.0.0",
2929
"@angular/core": "^7.0.0",
3030
"@angular/router": "^7.0.0",
31-
"@angular/cdk": "^7.0.0",
31+
"@angular/cdk": "^7.2.1",
3232
"rxjs": "^6.3.0",
3333
"nebular-icons": "^1.1.0"
3434
},
3535
"dependencies": {
3636
"intersection-observer": "0.5.0"
3737
},
3838
"schematics": "./schematics/collection.json"
39-
}
39+
}

0 commit comments

Comments
 (0)