I am developing an ionic app with a side menu.
In my app, i added a modal that contains three button. When i click on any button in that modal, it opens a new page. On that new page, i have header containing a button that is used to open the side menu.
Problem
Side menu opens normally on any page that isn't opened via buttons on modal but when i try to open the side menu on a page that was opened via button on a modal, instead of opening the side menu on that page, it opens the side menu behind the current page and when i press back button to go back to previous page, side menu can be seen opened on the previous page.
Question
What is causing this behavior and how can i fix it ?
Custom Modal typescript code
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams, ViewController } from 'ionic-angular';
import { LibraryPageSerice } from './libraryPage.service';
#IonicPage()
#Component({
selector: 'page-custom-posting-pop-up',
templateUrl: 'custom-posting-pop-up.html',
})
export class CustomPostingPopUpPage {
onLibraryPage: boolean;
constructor(private navCtrl: NavController, private navParams: NavParams,
private viewCtrl: ViewController,
private libService: LibraryPageSerice) {}
ionViewDidLoad() {
this.onLibraryPage = this.libService.onLibraryPage;
}
dismissModal(event) {
if(event.target.className === 'modal-container') {
this.viewCtrl.dismiss();
}
}
openCreationpage() {
this.viewCtrl.dismiss();
this.navCtrl.push('PostingCreationPage');
}
openSupportivePage() {
this.viewCtrl.dismiss();
this.navCtrl.push('PostingSupportivePage');
}
openLibraryPage() {
this.viewCtrl.dismiss();
this.navCtrl.push('MylibraryPage');
}
}
Custom modal html code
<div class="modal-container" (click)="dismissModal($event)">
<div class="modal">
<p>Posting Method</p>
<div class="btn-container">
<button class="creation-btn" (click)="openCreationpage()">My Creation</button>
<button class="supportive-btn" (click)="openSupportivePage()">Supportive</button>
<button *ngIf="!onLibraryPage" class="library-btn" (click)="openLibraryPage()">
My Library
</button>
</div>
</div>
</div>
This method is used to open the modal
posting() {
const modal = this.modalCtrl.create('CustomPostingPopUpPage');
modal.present();
}
If i don't use the modal and instead use an alert dialog to open the new page, side menu opens normally. So this problem only arises when i use a modal.
This is part of how modals are defined to work, "A Modal is a content pane that goes over the user's current page ... A modal uses the NavController to present itself in the root nav stack"
Because of this when you are calling this.navCtrl.push('PageName'); this instance of NavController is an Overlay Portal whereas a normal NavController not from a modal is a Nav. This will cause the page to be pushed along side your app-root (Which causes the results that you are witnessing).
Here are two solutions to this.
Pass in reference of NavController to your modal using NavParams
// home.ts
let modal = this.modalCtrl.create('ModalPage', {'nav': this.navCtrl});
// modal.ts
nav: Nav;
constructor(public navCtrl: NavController,
public navParams: NavParams,
public viewCtrl: ViewController) {
this.nav = this.navParams.get('nav');
}
openSupportivePage() {
this.viewCtrl.dismiss();
this.nav.push('PostingSupportivePage');
}
Or pass which page you want to open to viewCtrl.dismiss() and parse with onDidDismiss
// home.ts
modal.onDidDismiss((open_page) => {
if (open_page !== undefined && open_page.hasOwnProperty('open_page')) {
this.navCtrl.push(open_page['open_page']);
}
});
// modal.ts
openCreationpage() {
this.viewCtrl.dismiss({'open_page': 'PostingCreationPage'});
}
Related
After setting back button text using config,
it does not reflect right away in nav bar.
Have to pop and push the page again.
playground:
https://stackblitz.com/edit/backbuttonbug.
you can see in contact page,
setting back button text does not reflect in self page and even in other nav stack
code:
previous page:
export class AboutPage {
constructor(public navCtrl: NavController) {}
contact() {
this.navCtrl.push(ContactPage);
}
}
Next page:
export class ContactPage {
constructor(public navCtrl: NavController,
public config: Config) {}
toChinese() {
this.config.set("backButtonText", '返回');
}
toEnglish() {
this.config.set("backButtonText", 'back');
}
}
<ion-header>
<ion-navbar>
<ion-title>
Contact
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<button ion-button (tap)="toChinese()">toChinese</button>
<button ion-button (tap)="toEnglish()">toEnglish</button>
</ion-content>
I suspect this is a bug and have opened a issue:
https://github.com/ionic-team/ionic-v3/issues/976.
and find another issue similar:
https://github.com/ionic-team/ionic/issues/7043
is that a ionic bug / my program bug?
hope to see advice
You haven't added any code so I'm not 100% sure of what you've tried already but try this:
import { ViewController } from 'ionic-angular';
...
ionViewDidEnter() {
this.viewCtrl.setBackButtonText('Some dynamic button text');
}
Edit
Sorry didn't see your Stackblitz example, this works:
import { Component } from '#angular/core';
import { NavController, Config, ViewController } from 'ionic-angular';
#Component({
selector: 'page-contact',
templateUrl: 'contact.html'
})
export class ContactPage {
constructor(public navCtrl: NavController,
public config: Config,
private viewCtrl: ViewController) {
}
toChinese() {
this.viewCtrl.setBackButtonText('返回');
}
toEnglish() {
this.viewCtrl.setBackButtonText('Back');
}
}
I have code page.html to create tabs
<ion-tabs>
<ion-tab [root]="page1" [rootParams]="chatParams" tabTitle="Chat" tabIcon="chat"></ion-tab>
</ion-tabs>
and in page.ts is like below
export class samplePage {
page1: any = CarListPage;
page2: any = CarListPage;
page3: any = CarListPage;
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public bookingService: BookingProvider,
) {
}
when I open the page, the tab page is also displaying which is assigned in page.ts. Why it is displaying automatically without clicking that page could any please help me in this regard. It might be great help
I have a Modal in Ionic 4. I'd like to close it, when a user press the back button on her mobile (or the back button in her browser).
Does anyone know how I can do this?
EDIT: More details:
I have a button that opens my modal:
async onClick() {
const modal = await this.modalController.create({
component: Foo,
});
return await modal.present();
}
Component Foo doesn't have much more content than a button that closes the modal: this.modalController.dismiss();. So far so good.
On my mobile, however, the app now closes when the modal is open and the user taps the mobile's back button. But in this case only the modal should close.
Enol's answer helped me find a solution, thanks for that.
platform.registerBackButtonAction does no longer exist in v4. I tried platform.backButton.subscribe instead, but it didn't work. What works is this:
private backbuttonSubscription: Subscription;
constructor(private modalCtrl: ModalController) {
ngOnInit() {
const event = fromEvent(document, 'backbutton');
this.backbuttonSubscription = event.subscribe(async () => {
const modal = await this.modalCtrl.getTop();
if (modal) {
modal.dismiss();
}
});
}
ngOnDestroy() {
this.backbuttonSubscription.unsubscribe();
}
You can use the registerBackButtonAction method that Platform service contains. This method allows override the default native action of the hardware back button. The method accepts a callback function as parameter where you can implement your logic. In summary you should do the following:
Inject the Platform service inside the Foo component.
Call the registerBackButtonAction in the ngOnInit (or another init method) and pass a function callback as parameter that executes the logic to close the modal (this.modalController.dismiss();)
Clear the action when the modal component is closed (for example in ngOnDestroy method). To do that, the registerBackButtonAction returns a function that when is called the action is removed.
The code should be something like:
constructor(private platform: Platform) {
...
}
ngOnInit() {
this.unregisterBackAction = this.platform.registerBackButtonAction(() => {
this.modalController.dismiss();
})
}
ngOnDestroy() {
if(this.unregisterBackAction) this.unregisterBackAction();
}
For ionic 5 user
this.platform.backButton.subscribeWithPriority(999, async() => {
if (this.modalCtrl.getTop()) {
const modal = await this.modalCtrl.getTop();
console.log(modal)
if (modal) {
this.modalCtrl.dismiss();
return;
} else {
if (this.router.url=="/myrootpage" ) {
navigator['app'].exitApp();
} else {
this.navCtrl.pop();
}
}
} else {
if (this.router.url=="/myrootpage") {
navigator['app'].exitApp();
} else {
this.navCtrl.pop();
}
}
});
Yes, are almost on the way....
you just need to change in HTML part. I did in this way.
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-button color="dark" (click)="closeModal()">
<ion-icon name="arrow-back"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Create Pin</ion-title>
</ion-toolbar>
</ion-header>
after this, you just need to create a function that will close your modal popup.
in your ts file
closeModal() {
this.modalCtrl.dismiss();
}
I hope that will help you.
Based on the initial answer by Markus, You can decide to; Instead of unsubscribing after each back button event. You may want to listen to back-button events globally in your application and only call exit on specific pages.
import { fromEvent } from "rxjs"; // import fromEvent from rxjs
import { Router } from "#angular/router"; // import angular router as well
import { Location } from "#angular/common"; // import location from angular common
constructor(private router: Router, private location: Location) {
// Call the function when the app initializes at app.component.ts. it will watch for
// back button events globally in the application.
this.backButtonEvent();
}
// Function to present the exit alert
async exitAlert() {
const alert = await this.alertController.create({
// header: 'Confirm!',
message: "Are you sure you want to exit the app?",
buttons: [
{
text: "Cancel",
role: "cancel",
cssClass: "secondary",
handler: blah => {}
},
{
text: "Close App",
handler: () => {
navigator["app"].exitApp();
}
}
]
});
await alert.present();
}
// function to subscribe to the backbutton event
backButtonEvent(): void {
const event = fromEvent(document, "backbutton");
event.subscribe(async () => {
// When the current route matches a specific page/route in the app where u
// want to exit on back button press.
// else assume the user wants to navigate to a previous page
if(this.router.url === "<example page-url to exit from>") { this.exitAlert()
}
else { this.location.back() }
});
}
Update, for Ionic 5 (Angular)
in your-modal.page.ts
import { ModalController } from '#ionic/angular';
at the top of your modal's .ts file. Then in your constructor you can just denote a -public- relationship to the controller, that way it's accessible by your view.
also in your-modal.page.ts
constructor(
public modalCtrl: ModalController
) {}
Now you can inline the close command:
in your-modal.page.html
<ion-header color="dark">
<ion-toolbar color="dark">
<ion-title>Modal Title</ion-title>
<ion-buttons slot="primary">
<ion-button (click)="modalCtrl.dismiss()">
<ion-icon slot="icon-only" name="close"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
Slot "primary" makes the buttons move to the right in iOS.
You can also use the built in function of ionic which is
<ion-back-button>
</ion-back-button>
You can also position the <ion-back-button> to start or end
<ion-buttons slot="start">
<ion-back-button>
</ion-back-button>
</ion-buttons>
for more information about <ion-back-button>
Here's a link
Is there a way within Ionic to close a specific modal? Right now my flow is that I open a login modal and then the user can create an account which opens another modal. Upon successful signup, they get logged in and both modals should close but I'm only able to get the register closed.
this.closeModal();
this.viewCtrl.dismiss('LoginPage');
The second line does nothing. How would I dismiss the second modal after the first one closes? Any help would be great, thanks!
Pass a value success from the registration page. And on the login page access the value. If it is success then this.viewCtrl.dismiss().
Yiu have to dismiss the view in both pages.
You could return a result from the SignUpPage (true if the user was able to signup successfully), and check it in the SignInPage, to see if that modal should also be closed. It'd look like this:
#Component({
selector: 'page-sign-in',
templateUrl: 'sign-in.html'
})
export class SignInPage {
constructor(private viewCtrl: ViewController, private modalCtrl: ModalController) {}
// ...
// Method that redirects the user to the SignUpPage
public openSignUp(): void {
let modal = this.modalCtrl.create('SignUpPage');
modal.onDidDismiss(success => {
if (success) {
// Since this is also a modal, we should dismiss this view
this.viewCtrl.dismiss();
}
});
modal.present();
}
}
And...
#Component({
selector: 'page-sign-up',
templateUrl: 'sign-up.html'
})
export class SignUpPage {
constructor(private viewCtrl: ViewController) {}
// ...
// Method that redirects the user to the SignUpPage
public signUp(): void {
//...
// Return true if the user was able to sign up
this.viewCtrl.dismiss(true);
}
public close() {
// Close only this modal, but not the SignInPage modal
this.viewCtrl.dismiss(false);
}
}
The simplest solution to my problem was to just close one modal before opening another one.
After going through Clear History and Reload Page on Login/Logout Using Ionic Framework
I want to know same question, but for ionic2 using typescript.
On login and logout I need reload the app.ts, because there are classes that run libraries on construct.
it would be basically redirect to home and reload.
Found this answer here, (please note especially the line this.navCtrl.setRoot(this.navCtrl.getActive().component); which is by far the simplest solution that I've come across to reload present page for Ionic 2 & 3 and later versions of Angular (mine is 4), so credit due accordingly:
RELOAD CURRENT PAGE
import { Component } from '#angular/core';
import { NavController, ModalController} from 'ionic-angular';
#Component({
selector: 'page-example',
templateUrl: 'example.html'
})
export class ExamplePage {
public someVar: any;
constructor(public navCtrl: NavController, private modalCtrl: ModalController) {
}
refreshPage() {
this.navCtrl.setRoot(this.navCtrl.getActive().component);
}
}
If you want to RELOAD A DIFFERENT PAGE please use the following (note this.navCtrl.setRoot(HomePage);:
import { Component } from '#angular/core';
import { NavController, ModalController} from 'ionic-angular';
import { HomePage } from'../home/home';
#Component({
selector: 'page-example',
templateUrl: 'example.html'
})
export class ExamplePage {
public someVar: any;
constructor(public navCtrl: NavController, private modalCtrl: ModalController) {
}
directToNewPage() {
this.navCtrl.setRoot(HomePage);
}
}
Ionic 1
I haven't used Ionic 2 but currently i m using Ionic 1.2 and if they are still using ui-router than you can use reload: true in ui-sref
or you can add below code to your logout controller
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
Angular 2
Use
$window.location.reload();
or
location.reload();
You have to implement the CanReuse interface, and override the routerCanReuse to return false. Then, try calling router.renavigate().
Your component should look like this:
class MyComponent implements CanReuse {
// your code here...
routerCanReuse(next: ComponentInstruction, prev: ComponentInstruction) {
return false;
}
}
And then, when you perform login/logout, call:
// navigate to home
router.renavigate()
This is a hack, but it works.
Wrap the logic that follows your template adjustment in a setTimeout and that gives the browser a moment to do the refresh:
/* my code which adjusts the ng 2 html template in some way */
setTimeout(function() {
/* processing which follows the template change */
}, 100);
For ionic 2 it works for me when you force page reload by triggering fireWillEnter on a view controller
viewController.fireWillEnter();
Here is what worked for me to refresh only current page-
I am trying to call refreshMe function when I call onDelete from my view page,
See how my page.ts file looks-
export class MyPage {
lines of code goes here like
public arr1: any;
public arr2: any;
public constructor(private nav: NavController, navParams: NavParams) {
this.nav = nav;
this.arr1 = [];
this.arr2 = [];
// console.log("hey array");
}
onDelete() {
perform this set of tasks...
...
...
refreshMe()
}
refreshMe() {
this.nav.setRoot(MyPage);
}
}
This is just refreshing only current page.
We can also call this function from view if we need as--
<ion-col width-60 offset-30 (click)="refreshMe()">
....
....
</ion-col>
I personally use these three lines to totally refresh a component
let active = this.navCtrl.getActive(); // or getByIndex(int) if you know it
this.navCtrl.remove(active.index);
this.navCtrl.push(active.component);
You can use the ionViewWillLeave() to display your splashscreen while component is reloading and then hide it with ionViewDidEnter() once its loaded.
Hope it helps