How do I implement Ionic 4/Angular navigation in such a way that the user CANNOT navigate backwards though their entire experience (screens) on the application?
I've ported my Ionic 2 application to Ionic 4, and feel like I've lost some critical navigation functionality.
Specifically: as a user moves forward in the application, and bounces around the different areas of my application, they are now able use the Android back button to navigate backwards through the FULL HISTORY of their previous screes. Whereas previously Ionic would STOP them moving backwards once the user hit a root page.
For example, a user would navigate from the main Welcome Page, then to the main Products page, then to Product Details page, then to the main Orders page, and then Order Details page. Then, if they start to use the Android back button, they're allowed to navigate through the entire history of screens, all the way back to the Welcome Page.
Previously, they would be force stopped at the last root/main page (e.g. the Orders page).
I don't think I had to use any application specific logic to dynamically disable the Android back on the main pages. I think the previous versions of the Ionic framework was smart enough to stop going backwards too far.
How do I implement Ionic 4/Angular navigation in such a way that the user CANNOT navigate backwards though their entire experience (screens) on the application?
I understand that ionic 4 uses angular's routing.
I am NOT asking to disable the Android back button.
This is a much simpler solution that has been working for me. Essentially you just have to tell ionic/angular when you are about to navigate to a root page and then it will stop the back button taking you past it.
import { Router } from '#angular/router';
import { NavController } from '#ionic/angular';
...
constructor(private navCtrl: NavController, private router: Router) { }
...
this.navCtrl.setDirection('root');
this.router.navigateByUrl('/new-root-page');
In ionic v4 this seems to work fine:
in app.component.ts inside initializeApp() function add the following:
initializeApp() {
this.platform.ready().then(() => {
this.platform.backButton.subscribeWithPriority(9999, () => {
document.addEventListener('backbutton', function (event) {
event.preventDefault();
event.stopPropagation();
console.log('hello');
}, false);
});
// here put instructions for splashScreen, statusBar, etc.
});
}
Related
I am using ionic deeplinks. I have a service where I initialize the deeplink function like:
initDeepLink(nav: Nav) {
this.deeplinks.routeWithNavController(nav, {
'/page1/ PageComponent1,
})
}...
I call this function in my main app.component.ts , inside onAllReady() function, from the service with:
this.calldeepLinkServ.initDeepLink(this.nav);
where this.nav is of type:
#ViewChild(Nav) nav: Nav;
declared in app.component.ts
When I visit a deeplink on my device, it works fine and goes to the given page (PageComponent1), but there is always a blank page before it and then the transition sort of jumps and push the deeplink page.
It never push (slide from right) the new page in the top of the current one opened in my app. I was trying to put the #ViewChild(Nav) nav: Nav inside the deeplink service rather the app.component.ts, but it acts the same.
I also tried to see if there is a method to disable the native page push in this.deeplinks.routeWithNavController() but it does not have any properties like that (like animate: false for example which is available for NavController).
So I am really not sure how to prevent this bad navigation experience with deeplinks i am sure that this is not a typical transition for ionic deeplinks, it looks bad for UI.
So I've sorted this one out, instead:
this.deeplinks.routeWithNavController
I am using:
this.deeplinks.route
and than i check what is passed on inside the match.$link. So depending on the query send through like
if (match.$link['path'].indexOf('/page1/') !== -1) {...}
I call the nav push, with animate:false and it does not uses the default nav push animation.
I'm developing a PWA on ionic 3 with Angular 4 and I've failed multiple times trying to make a nice UI that show's in-app notifications about events.
I have a NotificationsService that is responsable for everything that has to do with getting the notification from Firebase.
My initial approach was to define a UI component (a.k.a notification-box) which would observe a property in the Notification Service and consume the notification provided by the service and display them nicely on top of the screen.
This sounds all nice and good but I created this component and had 3 issues:
Ionic 3 doesn't allow (AFAIK) a component to be 'global' and present in all app pages.
Including the tag of my component <notification-box></notification-box> on top of every page it's not a very good idea because components get instantiated and destroyed multiple times making it difficult to keep Subscriptions to the Observable notification property in the Service, and this could lead to a notification not arriving in between switching of pages.
If a notification where to arrive with a modal open, the notification would display behind the modal and my intent is to show notifications always on top.
I ended up using ToastController from ionic-angular which always displays on top no matter what (although it's a bit ugly and I want to switch to something like angular2-notifications).
How did Ionic achieve this "always on top" behaviour? Is there any way I can replicate that with a class of my own or Extend the ToastCtrl?
You can achieve what you want via provider and yes you will still need to inject such provider into every page that you want to see notifications in. You don't need to modify those pages' view (html templates) though.
I had similar need (to present "toast" inside of the app regardless of pages).
I solved this by making this provider a singleton provider (means we declare it at the app.module.ts in providers section) that is injected into every page (import and add to constructor):
import { Injectable } from '#angular/core';
import { ToastController } from 'ionic-angular'
#Injectable()
export class Toaster {
constructor (private toastCtrl: ToastController) {
}
presentToast(message, position, cssclass) {
let toast = this.toastCtrl.create({
message: message,
closeButtonText: "OK",
showCloseButton: true,
cssClass: cssclass,
position: position
});
toast.present();
}
presentSimpleToast(message, position) {
let toast = this.toastCtrl.create({
message: message,
duration: 3000,
position: position
});
toast.present();
}
}
When the user views the home screen for the first time - they are being sent there via this.nav.setRoot(Page). This presents an issue when I have three other pages settings root to a page. For example - I go to the home page, which is set root, so that home page data is loaded initially for the first time. Then the user navigates to the message page. Then the user goes back to the home page, the data is reloaded again. I don't want that to happen. I would like to only call it once, but due to setRoot, it refreshes the page. Just like how navCtrl.push(Page) and .pop, the data is not refreshed. I have a hamburger navigation style and that's why I have the set roots for each page in the hamburger navigation.
app.comp.ts
openPage() {
this.nav.setRoot(Page);
}
openPageTwo() {
this.nav.setRoot(MessagesPage);
}
How do I override the nav.setRoot refresh? Or use something else entirely?
Thanks
Exactly where are you refreshing your data? In what function?
Lifecycle events
I think your problem will be solved by using the correct lifecycle event. For example, ionViewDidLoad :
Runs when the page has loaded. This event only happens once per page being created. If a page leaves but is cached, then this event will not fire again on a subsequent viewing. The ionViewDidLoad event is good place to put your setup code for the page.
Have you tried refreshing your data there?
Global variable or service
As an alternative, you can create a global variable or a service that holds your data. Once you setRoot to a page for the first time, do the refresh and update the global value and do not refresh it the subsequent times that you setRoot to that page. This is not my favorite way, but will do the job for you.
Tabs:
Rather than setting roots several times, you may wanna try ionic tabs.
By setting a rootpage using navCtrl.setRoot(), you tell Ionic this page is the begin of the navigation tree of your application. For example, after a login, you should .setRoot(HomePage);
When you want to navigate from HomePage to MessagesPage, you should use navCtrl.push(), to pop the MessagesPage on top of the HomePage. eg; navCtrl.push(MessagesPage);
You can use a provider, since it is stored on memory once and every one that injects it will get its properties and data.
some-provider.ts
import { Injectable } from '#angular/core';
#Injectable()
export class SomeProvider {
public data: DataModel;
constructor(public http: Http) {
}
}
And then import that on your app's module providers variable.
After, get this provider on your component's constructor
some-page.ts
#Component({
selector: 'app-some-page',
templateUrl: 'app-some-page.html'
})
export class AppSomePage {
data: DataModel;
constructor(public someProvider: SomeProvider) {
this.data = this.someProvider.data;
}
}
I am learning ionic 2 and as part of my learning process, i am creating a basic ionic 2 app.
Below is a page from my app. I have some text contents which i would like to display in About page in app. Initially only title must be visible and once the user clicks on the title, another page with text content must be opened.
How do i achieve this? I mean, which component to use for this? Any guidance will be great. Any other approach/suggestion to achieve this is also welcome, i want the page to be clutter free.
To navigate from one page to another, You would have to use the navController offered by Ionic 2. Basically all navigation in Ionic 2 happens using the Stack data structure abstracted through the navController. This way you can push pages on top of other pages using
.push(ClassNameOfThePageYouWantToPush,{paramsYouWantToPassToTheNewPage})
And existing pages can be popped from the stack by calling
.pop(ClassNameOfThePageYouWantToPush,{paramsYouWantToPassToTheNewPage})
You can find more info here
To trigger it in the UI, use a (click) handler to call a function
<ion-title (click)="openNextPage()">About</ion-title>
In you .ts file you can then import the navController and add it to the constructor.
import { NavController, NavParams } from 'ionic-angular';
#Component({
selector: 'page-page2',
templateUrl: 'page2.html'
})
export class Page2 {
constructor(public navCtrl: NavController) {
}
openNextPage(){
this.navCtrl.push(PageYouWantToOpen);
}
}
Because this is such a common feature when you use the ionic 2 cli to generate a page
$: ionic g page my-page
It will automatically add the navController and navParams ready to be used.
I am creating an App with Ionic2 and the requirement is -
- the app when first loaded will show a Log In page and when logged in
- will have a Side-Menu enabled pages
The starter project shows that the Side Menu as the root of the app and loads first before any other page is open - then it loads the other related pages.
How can I build an app that Loads Log In page first and then set the Side Menu as the main navigation and never shows up the Log In screen??
I did this with ionic 1 but not being able to figure out with ionic2
Please help.
One solution would be to disable menu on Login screen and then to enable it after login.
You can disable menu by injecting MenuController and then use:
import {NavController, MenuController} from 'ionic-angular';
ionViewDidEnter() {
//to disable menu, or
this.menu.enable(false);
}
ionViewWillLeave() {
// to enable menu.
this.menu.enable(true);
}
#Digital IQ, you have to set your login page as the rootPage in your existing app.ts file and use MenuController in login page to make menu enable onPageDidLeave.
The example for this is available in ionic conference app where they have tutorial page before getting in to the actual application. Refer this for menu control and this (line 50) to set the initial page.
The above problem must have occurred because the user had surely logged in, but the changes i.e. setting it as the current user didn't take place in side menu page.
For that you can use Events API
Events is a publish-subscribe style event system for sending and responding to application-level events across your app.
For reference, go through the following answer-
Ionic 3 refresh side menu after login
kind Attn [vahid najafi & Aish123]
I tried something more easy and I found it working.
I set the LogIn page as the root when the app first loaded - and I removed 'menuToggle' button from this template.
Then I imported the Component I want to redirect on Log in
I created a singIn function in LogInPage class as follows:
signIn (){
let navRef = this.app.getComponent('nav');
navRef.setRoot(HelloIonicPage);
}
and it worked like a charm