Currently, I have been working on upgrading my current Ionic Cordova application from Ionic 3 to Ionic 5. In the process, the Angular routing has been throwing many errors and I was able to resolve most of them but when I try to change the root page for the application I always end up with a blank screen. I tried many online solutions but they did not work for me. Originally I tried the lazy loading method for all my pages but I found that it is a poor method so I changed it with direct imports. Currently, this is my app module:
@NgModule({
declarations: [MyAppPage,
],
entryComponents: [MyAppPage],
imports: [BrowserModule,
AppRoutingModule,
HttpClientModule,
IonicSignaturePadModule,
IonicModule.forRoot()],
providers: [
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
ApiService,
Device,
Camera,
InAppBrowser,
FingerprintAIO,
LocalNotifications,
Contacts,
BackgroundMode,
Keyboard,
Firebase,
Badge,
HttpClient,
IonicsignaturepadProvider,
],
bootstrap: [MyAppPage],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {}
This is my app routing file:
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
import {APP_BASE_HREF} from '@angular/common';
import {AuthPageModule} from './auth/auth.module';
import {CareTeamPageModule} from './care-team/care-team.module';
import {CommunitiesPageModule} from './communities/communities.module';
import {DashboardPageModule} from './dashboard/dashboard.module';
import {FaqPageModule} from './faq/faq.module';
import {ForgotPasswordPageModule} from './forgot-password/forgot-password.module';
import {ForgotUsernamePageModule} from './forgot-username/forgot-username.module';
import {FriendsPageModule} from './friends/friends.module';
import {HcsPageModule} from './hcs/hcs.module';
import {HistoryPageModule} from './history/history.module';
import {LoginPageModule} from './login/login.module';
import {MedicineDetailPageModule} from './medicine-detail/medicine-detail.module';
import {MedicinesPageModule} from './medicines/medicines.module';
import {NotificationsPageModule} from './notifications/notifications.module';
import {PrivacyPageModule} from './privacy/privacy.module';
import {ProfilePageModule} from './profile/profile.module';
import {SettingsPageModule} from './settings/settings.module';
import {SignupPageModule} from './signup/signup.module';
import {TermsPageModule} from './terms/terms.module';
import {WearablesPageModule} from './wearables/wearables.module';
const routes: Routes = [
{ path: '', redirectTo: 'login', pathMatch: 'full' },
{
path: 'login',
component: LoginPageModule
},
{
path: 'auth',
component: AuthPageModule,
},
{
path: 'care-team',
component: CareTeamPageModule
},
{
path: 'communities',
component: CommunitiesPageModule
},
{
path: 'dashboard',
component: DashboardPageModule
},
{
path: 'faq',
component: FaqPageModule
},
{
path: 'forgot-password',
component: ForgotPasswordPageModule
},
{
path: 'forgot-username',
component: ForgotUsernamePageModule
},
{
path: 'friends',
component: FriendsPageModule
},
{
path: 'hcs',
component: HcsPageModule
},
{
path: 'history',
component: HistoryPageModule
},
{
path: 'medicine-detail',
component: MedicineDetailPageModule
},
{
path: 'medicines',
component: MedicinesPageModule
},
{
path: 'notifications',
component: NotificationsPageModule
},
{
path: 'privacy',
component: PrivacyPageModule
},
{
path: 'profile',
component: ProfilePageModule
},
{
path: 'settings',
component: SettingsPageModule
},
{
path: 'signup',
component: SignupPageModule
},
{
path: 'terms',
component: TermsPageModule
},
{
path: 'wearables',
component: WearablesPageModule
},
];
@NgModule({
imports: [
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules, enableTracing: true, useHash: true }),
AuthPageModule,
CareTeamPageModule,
CommunitiesPageModule,
DashboardPageModule,
FaqPageModule,
ForgotPasswordPageModule,
ForgotUsernamePageModule,
FriendsPageModule,
HcsPageModule,
HistoryPageModule,
LoginPageModule,
MedicineDetailPageModule,
MedicinesPageModule,
NotificationsPageModule,
PrivacyPageModule,
ProfilePageModule,
SettingsPageModule,
SignupPageModule,
TermsPageModule,
WearablesPageModule,
],
providers: [{ provide: APP_BASE_HREF, useValue: '/' }, ],
exports: [RouterModule]
})
export class AppRoutingModule { }
This is the app component:
import {Component, ViewChild} from '@angular/core';
import { NavController, Platform, ToastController, MenuController} from '@ionic/angular';
import { Router } from '@angular/router';
import {DashboardPage} from './dashboard/dashboard.page';
import {MedicinesPage} from './medicines/medicines.page';
import {CareTeamPage} from './care-team/care-team.page';
import {HcsPage} from './hcs/hcs.page';
import {SettingsPage} from './settings/settings.page';
import {CommunitiesPage} from './communities/communities.page';
import {FaqPage} from './faq/faq.page';
import {WearablesPage} from './wearables/wearables.page';
import {NotificationsPage} from './notifications/notifications.page';
import {FriendsPage} from './friends/friends.page';
import {Keyboard} from '@ionic-native/keyboard/ngx';
import {ApiService} from './services/app.services';
import {BackgroundMode} from '@ionic-native/background-mode/ngx';
import {Firebase} from '@ionic-native/firebase/ngx';
import {Badge} from '@ionic-native/badge/ngx';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
@Component({
templateUrl: 'app.component.html',
selector: 'app-root',
})
export class MyAppPage {
@ViewChild(NavController) nav: NavController;
backButtonPressedOnceToExit: any;
menu: any;
document: any;
pages: Array<{ title: string, component: any, icon: string }>;
hideWaves: boolean;
bgInterval: any;
config: {
scrollAssist: false,
autoFocusAssist: false
};
constructor(public platform: Platform,
public splashScreen: SplashScreen,
private toastCtrl: ToastController,
private route: Router,
// tslint:disable-next-line:no-shadowed-variable
private ApiService: ApiService,
public menuCtrl: MenuController,
private keyboard: Keyboard,
private backgroundMode: BackgroundMode,
private fcm: Firebase,
private badge: Badge
) {
this.initializeApp();
this.hideWaves = false;
// used for an example of ngFor and navigation
this.pages = [
{title: 'Today\'s Meds', component: DashboardPage, icon: 'assets/imgs/menu-today-med.png'},
{title: 'Medicines', component: MedicinesPage, icon: 'assets/imgs/menu-medicine.png'},
{title: 'Healthcare Providers', component: CareTeamPage, icon: 'assets/imgs/menu-care-team.png'},
{title: 'Invite Friends', component: FriendsPage, icon: 'assets/imgs/menu-friends.png'},
{title: 'Communities', component: CommunitiesPage, icon: 'assets/imgs/menu-communities.png'},
{title: 'Connect to healthcare systems', component: HcsPage, icon: 'assets/imgs/menu-hcs.png'},
{title: 'Devices / Wearables', component: WearablesPage, icon: 'assets/imgs/menu-wearables.png'},
{title: 'Notifications', component: NotificationsPage, icon: 'assets/imgs/menu-notification.png'},
{title: 'Settings', component: SettingsPage, icon: 'assets/imgs/menu-setting.png'},
{title: 'Help & Support', component: FaqPage, icon: 'assets/imgs/menu-help.png'}
];
if (localStorage.getItem('userToken')) {
this.route.navigate(['auth']);
}else{
this.route.navigate(['login']);
}
}
initializeApp() {
this.platform.ready().then(() => {
// Clear badge
this.badge.clear();
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
// this.statusBar.styleDefault();
this.splashScreen.hide();
// this.backgroundMode.enable();
// this.keyboard.onKeyboardShow().subscribe( (value)=>{
// this.hideWaves = true;
// });
// this.keyboard.onKeyboardHide().subscribe( (value)=>{
// this.hideWaves = false;
// });
// this.platform.registerBackButtonAction(() => {
// if (this.backButtonPressedOnceToExit) {
// this.platform.exitApp();
// } else if (this.nav.canGoBack()) {
// this.nav.pop({});
// } else {
// this.menu.close(); //Close menu if open
// this.showToast();
// this.backButtonPressedOnceToExit = true;
// setTimeout(() => {
// this.backButtonPressedOnceToExit = false;
// },2000)
// }
// });
});
}
logout() {
this.menuCtrl.close();
this.menuCtrl.get().then((menu: HTMLIonMenuElement) => {
menu.swipeGesture = false;
});
this.ApiService.showToast('Logged Out');
localStorage.removeItem('userId');
localStorage.removeItem('userToken');
localStorage.removeItem('userDetails');
localStorage.removeItem('userNotifications');
}
profile() {
this.menuCtrl.close();
this.route.navigateByUrl('/profile');
}
async showToast() {
const toast = await this.toastCtrl.create({
message: 'Press Back Again To Exit The App',
duration: 3000,
position: 'bottom'
});
toast.present();
}
openPage(page) {
// Reset the content nav to have just this page
// we wouldn't want the back button to show in this scenario
this.nav.navigateRoot(page.component);
}
}
app.component.html:
<ion-menu [attr.content]="content" type="overlay" contentId="main">
<!-- <ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
-->
<ion-content>
<div class = "menu-header">
</div>
<div class="ion-text-center center-content relative" (click) = "profile()">
<img id = "userPicture" alt = "" src = "assets/imgs/user-default.png" />
<div class = "profile-edit">
<div class="ion-text-center">
<img alt = "" src = "assets/imgs/camera_green.png" />
</div>
</div>
</div>
<ion-list class = "menu-list">
<button menuClose ion-item *ngFor="let p of pages" (click)="openPage(p)">
<img [src] = "p.icon" item-left />
{{p.title}}
</button>
</ion-list>
<div class="ion-text-right logout" (click) = "logout()">
Logout
</div>
</ion-content>
</ion-menu>
<!-- Disable swipe-to-go-back because it's poor UX to combine STGB with side menus -->
<ion-app>
<router-outlet></router-outlet>
</ion-app>
login page routing module:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { IonicModule } from '@ionic/angular';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { LoginPage } from './login.page';
const routes: Routes = [
{
path: '',
component: LoginPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes),
IonicModule,
CommonModule,
FormsModule],
exports: [RouterModule],
})
export class LoginPageRoutingModule {}
login.page.ts:
import { Component, OnInit } from '@angular/core';
import { NavController, Platform, NavParams, MenuController } from '@ionic/angular';
import {Routes, RouterModule, Router, ActivatedRoute} from '@angular/router';
import { ApiService } from '../services/app.services';
import { LoadingController } from '@ionic/angular';
import {NavigationExtras} from '@angular/router';
import { StatusBar } from '@ionic-native/status-bar/ngx';
@Component({
selector: 'app-login',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss'],
providers: [NavParams]
})
export class LoginPage implements OnInit {
public navParams: NavParams;
loginState: string;
user: any;
loading: any;
hideWaves: boolean;
origCode: number;
showForgotPassword: boolean;
userMobile: number;
passwordType = 'password';
passwordIcon = 'eye-off';
constructor(private route: Router,
public navCtrl: NavController,
public statusBar: StatusBar,
private loadingCtrl: LoadingController,
private ApiService: ApiService,
public menuCtrl: MenuController,
public platform: Platform,
private actRoute: ActivatedRoute,
) {
this.loginState = 'init';
this.showForgotPassword = false;
this.user = {};
this.actRoute.queryParams.subscribe(params => {
if (route.getCurrentNavigation().extras.state) {
this.loginState = route.getCurrentNavigation().extras.state.item;
}
});
this.menuCtrl.get().then((menu: HTMLIonMenuElement) => {
menu.swipeGesture = false;
});
this.statusBar.backgroundColorByHexString('#000000');
this.statusBar.styleLightContent();
}
ngOnInit() {
this.platform.ready().then(() => {
// let video = this.mVideoPlayer.nativeElement;
// video.src = "assets/video/clinakos_video.mp4";
// video.load();
});
}
ionViewWillLeave() {
// the .nativeElement property of the ViewChild is the reference to the tag <video>
// this.mVideoPlayer.nativeElement.src = '';
// this.mVideoPlayer.nativeElement.load();
}
signUp() {
this.navCtrl.navigateRoot('/signup');
}
signIn() {
if ( (this.user.username) && (this.user.password) ) {
this.loading = this.loadingCtrl.create({
message: 'Please wait...'
});
this.loading.present();
this.ApiService.login(this.user)
.then(r => {
localStorage.setItem('userToken', r.token);
localStorage.setItem('userId', r.userId);
// Check if user has reminders.
this.ApiService.getReminders()
.then(r => {
this.loading.dismiss();
this.navCtrl.navigateRoot('/dashboard');
this.ApiService.showToast('Logged In');
})
.catch(e => {
this.navCtrl.navigateRoot('/medicines');
this.loading.dismiss();
this.ApiService.showToast('Logged In');
});
this.menuCtrl.enable(true);
this.menuCtrl.get().then((menu: HTMLIonMenuElement) => {
menu.swipeGesture = true;
});
if (localStorage.getItem('userNotifications') === null) {
localStorage.setItem('userNotifications', JSON.stringify([]));
}
})
.catch(e => {
console.log (e);
if (e.status == '404') {
this.ApiService.showToast('User does not exist');
}
if (e.status == '400') {
this.ApiService.showToast('Invalid credentials');
this.showForgotPassword = true;
}
this.loading.dismiss();
});
} else {
this.ApiService.showToast('Please enter username and password');
}
}
terms() {
this.navCtrl.navigateForward('/terms');
}
privacy() {
this.navCtrl.navigateForward('/privacy');
}
navigateForgotPasswd() {
const navigationExtras: NavigationExtras = { state: { user: this.user } };
this.navCtrl.navigateForward('/forgot-password', navigationExtras);
}
navigateForgotUserName() {
const navigationExtras: NavigationExtras = { state: { user: this.user } };
this.navCtrl.navigateForward('/forgot-username', navigationExtras);
}
hideShowPassword() {
this.passwordType = this.passwordType === 'text' ? 'password' : 'text';
this.passwordIcon = this.passwordIcon === 'eye-off' ? 'eye' : 'eye-off';
}
}
This is the login-routing.module:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { IonicModule } from '@ionic/angular';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { LoginPage } from './login.page';
const routes: Routes = [
{
path: '',
component: LoginPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes),
IonicModule,
CommonModule,
FormsModule],
entryComponents: [LoginPage],
exports: [RouterModule],
})
export class LoginPageRoutingModule {}
This is the error I am receiving when the app tries to startup and move to the login page:
"error: Error: No component factory found for LoginPageModule. Did you add it to @NgModule.entryComponents?)"