Nativescript-angular: ModalDialogService - no way to close the modal programatically

Created on 9 Feb 2017  路  18Comments  路  Source: NativeScript/nativescript-angular

Unless I am missing something, there is no clear way to close the modal created by showmodal on the ModalDialogService.

Under the hood, showmodal is called on the page pulled out of the viewcontainerref, but closemodal is called on the modal itself.

I can't get to the page that is the modal because it is in a private static func, and if I pull the get(Page) off the viewcontainerref and call closemodal on it or call closemodal on the page I am on in the app, the grayed out background stays.

This is of course in the instances where I am navigating away because of something else that has happened and the close button on the modal is not going to get touched.

I can post code, but it is mostly this to show the modal:

        let options: ModalDialogOptions = {
            viewContainerRef: this.viewContainerRef,
            context: {}
        }

        this.modalService.showModal(MyModalType, options).then((result: MyResultType) => {

        })

then this to navigate away:

    this.routerExtensions.navigate(["/home"], { clearHistory: true }).then(() => {
        this.submitted = false
    })

Ive tried this to try to close the modal:

            let refPage: Page = this.viewContainerRef.injector.get(Page)
            refPage.closeModal()
            this.page.modal.closeModal()

or just calling close on my current page, but neither works.

this.page.closeModal()

I have also tried getting the modal's button by calling this.page.getViewById, but its in a different page and doesn't return. And tried passing a func back and forth between my page through params, but that doesnt seem to work consistently.

thoughts?

question

Most helpful comment

Probably not the best way but what I'm doing at the moment is to use Observables to implement this functionality. I wanted to implement the typical Android loading popup. This is what I did

Pop up component

import {Component} from "@angular/core";
import {ModalDialogParams} from "nativescript-angular/modal-dialog";

@Component({
    template: `
        <StackLayout orientation="horizontal" padding="20" horizontalAlignment="left" verticalAlignment="center">
            <ActivityIndicator busy="true" height="50" width="50"
                       visibility="visible"></ActivityIndicator>
            <Label margin="10 5 0 5" text="Loading ..."></Label>           
        </StackLayout>
    `
})
export class LoadingPopUpComponent {

    constructor(private params: ModalDialogParams) {

        params.context.closeObserver.subscribe((r) => {
            this.close(null);
        });
    }

    public close(result: string) {
        this.params.closeCallback(result);
    }
}

Opening and closing the modal

loadingIndicator(): void {
        let options: ModalDialogOptions = {
            context: {closeObserver: this.dialogObservable},
            fullscreen: false,
            viewContainerRef: this.viewContainerRef
        };

        this.modalService.showModal(LoadingPopUpComponent, options);
    }

    closeIndicator(): void {
        this.dialogSubject.next(true);
    }

I define the Subject and observable as follows

dialogSubject: Subject<boolean>;
dialogObservable: Observable<boolean>;
this.dialogSubject = new Subject();
this.dialogObservable = this.dialogSubject.asObservable();

Hope it helps.

All 18 comments

Sorry, closed this pre-emptively

Re-opening, I closed it thinking that I had to be doing something wrong, but if I am, I sure can't figure it out. Any thoughts?

This should do the trick:

import { topmost } from "ui/frame";

...

const page = topmost().currentPage;
if (page && page.modal) {
page.modal.closeModal()
}

@DavyDeDurpel thanks! that partially works, it gets rid of the modal, but not the gray overlay from what I assume is it being full screen.

Thoughts?

edit: actually, I'll get back to you, it seems like the gray overlay is because the navigation or something is getting broken when I call that, but there is too much going on for me to know yet.

I never had the issue of the gray overlay not disappearing. Did you try first closing the modal and than navigating away?

Hi @bot2600,
The correct way to use a ModalPage with navigation in NativeScript is, as @DavyDeDurpel suggested, to close the modal page and then to make the navigation. To be able to access the Page in the project, you could set up new private page property in the constructor of the component. For example:

import { Component, OnInit, NgModule } from "@angular/core";
import { ModalDialogParams } from "nativescript-angular/modal-dialog";
import { Page } from "ui/page";

@Component({
    moduleId: module.id,
    templateUrl: "./modal-view.html",
})
export class ModalViewComponent implements OnInit {

    constructor(private params: ModalDialogParams, private page: Page) {
    }

    ngOnInit() {
    }


}

The navigation could be made after returning from the modal Page:

this._modalService.showModal(ModalViewComponent, options)
            .then((result: string) => {
                if (args === "navigate") {
                    this.routerExtensions.navigate(["/main"], { clearHistory: true });
                } else if (args === "findTheDay") {
                    //do something else
                }
            });

For further help, you could also review the sample code in nativescript-sdk-examples-ng repo

@tsonevn thanks, edited my response, responded before I had my coffee, but I think I see what you are saying. Even if I close it manually, go ahead and do the navigation in the then :)

Sounds like that will work, I'll verify and close this if it does. I do still think there should be a more obvious way to programmatically close a modal when using modal service, but this will get me going for now.

Thanks again to both of you.

Ok, so back from testing, the code Davy gave me works under some circumstances, but under others isn't even though page and modal are both true. I have this code:

            console.log("I BELIEVE I CAN FLY")
            let page = topmost().currentPage
            if (page && page.modal) {
                console.log("trying to close the modal")
                page.closeModal()
            }

both get logged to the console, but the then from the showmodal does not get hit and the modal is not closed.

Probably not the best way but what I'm doing at the moment is to use Observables to implement this functionality. I wanted to implement the typical Android loading popup. This is what I did

Pop up component

import {Component} from "@angular/core";
import {ModalDialogParams} from "nativescript-angular/modal-dialog";

@Component({
    template: `
        <StackLayout orientation="horizontal" padding="20" horizontalAlignment="left" verticalAlignment="center">
            <ActivityIndicator busy="true" height="50" width="50"
                       visibility="visible"></ActivityIndicator>
            <Label margin="10 5 0 5" text="Loading ..."></Label>           
        </StackLayout>
    `
})
export class LoadingPopUpComponent {

    constructor(private params: ModalDialogParams) {

        params.context.closeObserver.subscribe((r) => {
            this.close(null);
        });
    }

    public close(result: string) {
        this.params.closeCallback(result);
    }
}

Opening and closing the modal

loadingIndicator(): void {
        let options: ModalDialogOptions = {
            context: {closeObserver: this.dialogObservable},
            fullscreen: false,
            viewContainerRef: this.viewContainerRef
        };

        this.modalService.showModal(LoadingPopUpComponent, options);
    }

    closeIndicator(): void {
        this.dialogSubject.next(true);
    }

I define the Subject and observable as follows

dialogSubject: Subject<boolean>;
dialogObservable: Observable<boolean>;
this.dialogSubject = new Subject();
this.dialogObservable = this.dialogSubject.asObservable();

Hope it helps.

@dgomezs thanks, yeah I did something similar except I think I used a broadcaster, I forgot this was open and it doesnt look like its getting any traction so I'll just go ahead and close it.

Since it's been a while: Is there any new way to close an opened modal?

Funny but I just simply called the closeCallBack() which I couldn't figure out how to assign (since it's supposed to be a callback function, but it simply closed the modal page.

closeWindow(event) {
    this.params.closeCallback()
}

look like an issue using {N} angular,
this.modalSvc.showModal(MdtcellComponent, options).then((res) => { console.dir(res); let url = res.url ; let param = res.param ; this.route.navigate(['/'+ url + '/'+ param],{ clearHistory: true }); })

after modal close, the page navigate to url but after few second it`will back to previous page where the modal tap

everything is working fine except closing .. please anyone if found the answer post it here in pure javascript version.....

@freddiandrew @vick16ach @bot2600

I opened a feature request as I have run into the same modal close nav back issue. Maybe it can get some traction or at least the conversation going again.

https://github.com/NativeScript/nativescript-angular/issues/1534

@kkoates I hope it will be picked up. I have the same issue. I can close the modal in iOS, but not in Android (and I mean from outside the modal). For now I think I also will use a Observable or something.

Here is what I ended up doing to close a model from another class using an interface. https://play.nativescript.org/?template=play-ng&id=q1mDZI&v=6

@dgomezs
Thanks a lot for the solution. It works fine. (Couldn't find any other working solution till date.)
Any downside of using such a solution?

Was this page helpful?
0 / 5 - 0 ratings