diff --git a/e2e/modal-navigation-ng/app/navigation/basic.navigation.component.ts b/e2e/modal-navigation-ng/app/navigation/basic.navigation.component.ts index 54c818612..ad0cd0031 100644 --- a/e2e/modal-navigation-ng/app/navigation/basic.navigation.component.ts +++ b/e2e/modal-navigation-ng/app/navigation/basic.navigation.component.ts @@ -1,4 +1,4 @@ -import { Component, ViewContainerRef, Input } from "@angular/core"; +import { Component, ViewContainerRef, Input, ViewChild, ElementRef } from "@angular/core"; import { Router, NavigationEnd } from "@angular/router"; import { ModalDialogService, ModalDialogOptions } from "nativescript-angular/directives/dialogs"; import { ModalComponent } from "../modal/modal.component"; @@ -17,11 +17,13 @@ import { ModalViewComponent } from "~/modal-shared/modal-view.component"; + ` }) export class BasicsNavigationComponent { + @ViewChild("popoverButtonComp") popoverButtonComp: ElementRef; @Input() col: number; constructor( private modal: ModalDialogService, @@ -29,7 +31,7 @@ export class BasicsNavigationComponent { private vcf: ViewContainerRef, private viewContainerRefService: ViewContainerRefService) { } - + onModalNoFrame() { const options: ModalDialogOptions = { context: { @@ -74,14 +76,28 @@ export class BasicsNavigationComponent { onRootModalTap(): void { const options: ModalDialogOptions = { - viewContainerRef: this.viewContainerRefService.root, - context: {}, - fullscreen: true + viewContainerRef: this.viewContainerRefService.root, + context: {}, + fullscreen: true }; - + this.modal.showModal(ModalViewComponent, options) - .then((result: string) => { - console.log(result); - }); - } + .then((result: string) => { + console.log(result); + }); + } + + onPopoverModal() { + const options: ModalDialogOptions = { + viewContainerRef: this.viewContainerRefService.root, + context: {}, + ios: { + presentationStyle: UIModalPresentationStyle.Popover + }, + target: this.popoverButtonComp.nativeElement + }; + + this.modal.showModal(ModalViewComponent, options) + .then((result: string) => { console.log(result);}); + } } diff --git a/e2e/modal-navigation-ng/package.json b/e2e/modal-navigation-ng/package.json index 444d4b4ee..fc6209dc9 100644 --- a/e2e/modal-navigation-ng/package.json +++ b/e2e/modal-navigation-ng/package.json @@ -46,6 +46,7 @@ "nativescript-dev-appium": "next", "nativescript-dev-typescript": "next", "nativescript-dev-webpack": "next", + "tns-platform-declarations": "next", "typescript": "~3.1.1" }, "scripts": { diff --git a/e2e/modal-navigation-ng/references.d.ts b/e2e/modal-navigation-ng/references.d.ts new file mode 100644 index 000000000..b945d69c5 --- /dev/null +++ b/e2e/modal-navigation-ng/references.d.ts @@ -0,0 +1 @@ +/// \ No newline at end of file diff --git a/nativescript-angular/directives/dialogs.ts b/nativescript-angular/directives/dialogs.ts index 7c8b45739..51363c032 100644 --- a/nativescript-angular/directives/dialogs.ts +++ b/nativescript-angular/directives/dialogs.ts @@ -6,7 +6,7 @@ import { NgModuleRef, ReflectiveInjector, Type, - ViewContainerRef, + ViewContainerRef } from "@angular/core"; import { NSLocationStrategy } from "../router/ns-location-strategy"; @@ -18,14 +18,15 @@ import { DetachedLoader } from "../common/detached-loader"; import { PageFactory, PAGE_FACTORY } from "../platform-providers"; import { once } from "../common/utils"; import { topmost, Frame } from "tns-core-modules/ui/frame"; +import { ShowModalOptions } from "tns-core-modules/ui/core/view"; -export interface ModalDialogOptions { +export type BaseShowModalOptions = Pick>; + +export interface ModalDialogOptions extends BaseShowModalOptions { context?: any; - fullscreen?: boolean; - animated?: boolean; - stretched?: boolean; viewContainerRef?: ViewContainerRef; moduleRef?: NgModuleRef; + target?: View; } export class ModalDialogParams { @@ -35,13 +36,10 @@ export class ModalDialogParams { } } -interface ShowDialogOptions { +interface ShowDialogOptions extends BaseShowModalOptions { containerRef: ViewContainerRef; context: any; doneCallback; - fullscreen: boolean; - animated: boolean; - stretched: boolean; pageFactory: PageFactory; parentView: ViewBase; resolver: ComponentFactoryResolver; @@ -54,16 +52,20 @@ export class ModalDialogService { } public showModal(type: Type, - { viewContainerRef, moduleRef, context, fullscreen, animated, stretched }: ModalDialogOptions + options: ModalDialogOptions ): Promise { - if (!viewContainerRef) { + if (!options.viewContainerRef) { throw new Error( "No viewContainerRef: " + "Make sure you pass viewContainerRef in ModalDialogOptions." ); } - let parentView = viewContainerRef.element.nativeElement; + let parentView = options.viewContainerRef.element.nativeElement; + if (options.target) { + parentView = options.target; + } + if (parentView instanceof AppHostView && parentView.ngAppRoot) { parentView = parentView.ngAppRoot; } @@ -75,11 +77,11 @@ export class ModalDialogService { parentView = parentView._ngDialogRoot; } - const pageFactory: PageFactory = viewContainerRef.injector.get(PAGE_FACTORY); + const pageFactory: PageFactory = options.viewContainerRef.injector.get(PAGE_FACTORY); // resolve from particular module (moduleRef) // or from same module as parentView (viewContainerRef) - const componentContainer = moduleRef || viewContainerRef; + const componentContainer = options.moduleRef || options.viewContainerRef; const resolver = componentContainer.injector.get(ComponentFactoryResolver); let frame = parentView; @@ -93,16 +95,14 @@ export class ModalDialogService { setTimeout(() => { try { this._showDialog({ - containerRef: viewContainerRef, - context, + ...options, + containerRef: options.viewContainerRef, + context: options.context, doneCallback: resolve, - fullscreen, - animated, - stretched, pageFactory, parentView, resolver, - type, + type }); } catch (err) { reject(err); @@ -111,23 +111,12 @@ export class ModalDialogService { }); } - private _showDialog({ - containerRef, - context, - doneCallback, - fullscreen, - animated, - stretched, - pageFactory, - parentView, - resolver, - type, - }: ShowDialogOptions): void { + private _showDialog(options: ShowDialogOptions): void { let componentView: View; let detachedLoaderRef: ComponentRef; const closeCallback = once((...args) => { - doneCallback.apply(undefined, args); + options.doneCallback.apply(undefined, args); if (componentView) { componentView.closeModal(); this.location._closeModalNavigation(); @@ -136,15 +125,15 @@ export class ModalDialogService { } }); - const modalParams = new ModalDialogParams(context, closeCallback); + const modalParams = new ModalDialogParams(options.context, closeCallback); const providers = ReflectiveInjector.resolve([ { provide: ModalDialogParams, useValue: modalParams }, ]); - const childInjector = ReflectiveInjector.fromResolvedProviders(providers, containerRef.parentInjector); - const detachedFactory = resolver.resolveComponentFactory(DetachedLoader); - detachedLoaderRef = containerRef.createComponent(detachedFactory, -1, childInjector, null); - detachedLoaderRef.instance.loadComponent(type).then((compRef) => { + const childInjector = ReflectiveInjector.fromResolvedProviders(providers, options.containerRef.parentInjector); + const detachedFactory = options.resolver.resolveComponentFactory(DetachedLoader); + detachedLoaderRef = options.containerRef.createComponent(detachedFactory, -1, childInjector, null); + detachedLoaderRef.instance.loadComponent(options.type).then((compRef) => { const detachedProxy = compRef.location.nativeElement; if (detachedProxy.getChildrenCount() > 1) { @@ -157,9 +146,7 @@ export class ModalDialogService { (componentView.parent).removeChild(componentView); } - // TODO: remove cast after https://github.com/NativeScript/NativeScript/pull/5734 - // is in a published version of tns-core-modules. - (parentView).showModal(componentView, context, closeCallback, fullscreen, animated, stretched); + options.parentView.showModal(componentView, { ...options, closeCallback }); }); } }