(Disclaimer: I am still very new to ionic and coding in general, if any terminology below is wrong please let me know as part of my learning process. Thanks in advance for help)
Problem: Sidemenu show after is pressed, but the menu cannot be clicked
Background: I have an ionic project setup with side menu in split pane. It was structured with a separate ionic page for the menu, route directly from root page to lazy-load the menu page, then from there the menu routing module handle the child route to display different pages.
I have these setup up by following through this youtube tutorial https://www.youtube.com/watch?v=I82_roQSgco
Long story short, after building up my app and now wanting to setup route guard, I personally found it makes no sense to have an empty app component and route to a menu as an entry point. So I want to move the menu and the routing logic back into the app component and app routing.
Everything seems fine with the migration, except for the side-menu. the side-menu will show if I press the menu toggle button, but the buttons in the menu are unclickable as if there is another element overlay on top of it. However, if I use a full width browser, where the menu is not hidden in the first place, it works just fine.
I simply moved everything in the html template from the menu page into that of the app component html template within the tab.
I spent hours troubleshooting with reference to the default side-menu app and my previously working strategy, and I still cannot figure out why I cannot click the menu.
code attached below, any help appreciated
app-routing.module.ts
import { NgModule } from '#angular/core';
import { PreloadAllModules, RouterModule, Routes } from '#angular/router';
import { AngularFireAuthGuard, redirectUnauthorizedTo } from "#angular/fire/auth-guard";
import { AppComponent } from './app.component';
const redirectToLogin = () => redirectUnauthorizedTo(['login']);
const routes: Routes = [
{
//authguard to be implement in the root path
path: '',
component:AppComponent,
children:[
{
path: 'users',
loadChildren: './pages/users/users.module#UsersPageModule'
},
{
path: 'students',
loadChildren: './pages/students/students.module#StudentsPageModule'
},
{
path: '',
loadChildren: './pages/home/home.module#HomePageModule'
},
]
},
{
//redirect to login page if not logged in
path: 'login',
loadChildren: './pages/login/login.module#LoginPageModule'
}
];
#NgModule({
imports: [
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.component.html
<ion-app>
<ion-split-pane contentId ="content">
<ion-menu contentId="content">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-menu-toggle auto-hide="false" *ngFor = "let p of pages">
<ion-item [routerLink]="p.url" routerDirection="root" [class.active-item]="selectedPath === p.url">
{{p.title}}
</ion-item>
</ion-menu-toggle>
</ion-list>
</ion-content>
</ion-menu>
<ion-router-outlet id="content" main></ion-router-outlet>
</ion-split-pane>
</ion-app>
app.component.ts
import { Component, OnInit } from '#angular/core';
import { Platform } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { Router, RouterEvent } from '#angular/router';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss']
})
export class AppComponent implements OnInit{
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
private router:Router,
) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleDefault();
this.splashScreen.hide();
});
}
pages = [
{
title:'Home',
url:''
},
{
title:'Students',
url:'students'
},
{
title:'Users',
url:'users'
}
]
selectedPath = '';
ngOnInit(){
this.router.events.subscribe((event:RouterEvent) =>{
this.selectedPath = event.url;
});
}
}
home.page.html (an empty home page with the ion-menu-button)
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>Home</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
</ion-content>
You are forcing your router-outlet to use App-component as a component, when App-component is loaded by default. Easy solution is to change your routes const
const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{
path: 'users',
loadChildren: './pages/users/users.module#UsersPageModule'
},
{
path: 'students',
loadChildren: './pages/students/students.module#StudentsPageModule'
},
{
path: '',
loadChildren: './pages/home/home.module#HomePageModule'
},
];
for sub component inside router i suggest you to watch this video: https://youtu.be/hkaa2mnqOI8
Related
My application requires a brand code to determine the style and dom.
currently the on load my URL would be www.SiteName.com/HBL (HBL = brandName)
It is a simple site where it has the only header, footer, search component.
but I need to get the Brand info from service api.
So in Appcomponent.ts, I injected ActivatedRoute and in the ngOnInit method, I subscribed paramMap.
When I load the app I am getting null parameter value.
This what I have done
my app.compnent.html:
<div class="container">
<header [brand]="brand"></header>
<!-- <esw-search></esw-search> -->
<router-outlet></router-outlet> - Search will be populated thru route
<esw-footer></esw-footer>
</div>
I could have avoided router but sometimes the search page will be directly accessible.
like www.SiteName.com/HBL/search?trackingnumber=123456;language=en
my routing component:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { NotFoundComponent } from './notfound/notfound.component';
import { SearchComponent } from './tracking-search/search/search.component';
const routes: Routes = [
{ path: '', component: SearchComponent },
{ path: ':brandName/search', component: SearchComponent },
{ path: ':brandName/', component: SearchComponent },
{ path: '404', component: NotFoundComponent },
{ path: '**', redirectTo: '404' }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
my appcomponent.ts code:
#Component({
selector: 'esw-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
title = 'logistics-tracking-ui';
apiUrl: string;
brand: Brand;
constructor(
private tracking: TrackingService,
private route: ActivatedRoute) {
}
ngOnInit(): void {
this.route.paramMap.subscribe(params => {
const brandName = params.get('brandName');
this.tracking.getBrandData(brandName).subscribe((response) => this.brand = response);
});
}
}
}
SearchComponent.htm:
<div class="card-body">
<div class="card mx-auto">
<div class="card-body">
<h3 style=" text-align: center"> Track your International Package</h3>
<div>
<span class="ui-float-label">
<input [(ngModel)]="trackingNumber" id="float-input" type="text" size="30" pInputText>
<label for="float-input">Tracking Number</label>
</span>
<button pButton type="button" label="Click" (click)="searchTracking()"></button>
</div>
<esw-search-details [trackingDetails]='trackingDetails$'></esw-search-details>
</div>
</div>
</div>
searchComponent.ts:
#Component({
selector: 'esw-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.scss']
})
export class SearchComponent implements OnInit {
trackingNumber = '';
trackingDetails$: Observable<any>;
constructor(private trackingservice: TrackingService) { }
ngOnInit() {
}
searchTracking(): void {
alert('Search Clicked' + this.trackingNumber);
if (!this.trackingNumber.trim()) {
// if not search term, return empty hero array.
// Publish error message
console.log('Invalid Input');
return;
}
this.trackingDetails$ = this.trackingservice.getTrackingDetails(this.trackingNumber, 'en-GB');
}
Note: I have not added much logic to search & serachDetails component.
The issue's I have:
Access brand params value in App component.
Is this right approach to defining layout in app.coponent.html?
Is there any better approach I can use for this?
Sorry this is my first angular project, any help will be appriciated.
May be you need to add a route for the param and that has to be added as the first in the list of routes, like
const routes: Routes = [
{ path: ':brandName/:brand', component: SearchComponent },
{ path: ':brandName/search', component: SearchComponent },
{ path: ':brandName/', component: SearchComponent },
{ path: '404', component: NotFoundComponent },
{ path: '', component: SearchComponent },
{ path: '**', redirectTo: '404' }
];
and now in the app component we can access it like:-
this.route.paramMap.subscribe(params => {
const brandName = params['brand']
this.tracking.getBrandData(brandName).subscribe((response) => this.brand = response);
});
If you want to go the route you are with passing the the exports/imports, then you have to be careful of the asynchronous loading of JS. Assuming your api call, exports, and imports are set up correctly, the Api call is completed and the brand is filled after the header component is loaded, (verify by adding console log in the app component after the api call is completed. You'll see it logs after the header loads, making it inaccessible to the header component's ngOnInit method). So you can either prevent loading until you have the required element:
<header *ngIf="ReturnedObject.brand" [brand]="brand"></header>
Or you can load the element after the page is loaded with Ng life cycle hooks, such as
ngAfterContentInit(){}
(this is not a great option as your page will load with whatever default branding, then it will reload once the brand is updated)
my preferred method
You can use the "{{}}" notation to dynamically name your class of an element as needed, and instead of passing an export to load another component, set the class in the parent component, then load the child component:
(in your child css)
.texas {
background-image: texasFlag.png;
}
.newYork {
background-image: newYorkFlag.png;
}
(in your parent html)
<header class="{{ReturnedObject.brand}}"></header>
<your-child-component></your-child-component>
<footer class="{{ReturnedObject.brand}}"></footer>
That way, the class is already set by the parent before the child starts to load, taking away the "racing" your parent and child component are doing to load.
I'm trying to incorporate a Firebase database into my Ionic application using Angular. I was following the instructions laid out on the AngularFire github page (https://github.com/angular/angularfire2) but when I actually run the application I keep getting a null response. I also am confused on the input of the of the db.object method (db.object('item')). What does 'item' actually represent?
This is my app.component.ts file
import { Component } from '#angular/core';
import { Platform } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { MenuController } from '#ionic/angular';
import { AngularFireDatabase } from '#angular/fire/database';
import { Observable } from 'rxjs';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent {
item: Observable<any>;
example: Observable<any>;
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
private menu: MenuController,
private db: AngularFireDatabase
){
this.item = db.object('item').valueChanges();
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleDefault();
this.splashScreen.hide();
});
}
close(){
this.menu.close();
}
}
This is my app.component.html file
<ion-app>
<ion-menu side="start" menuId="first">
<ion-header>
<ion-toolbar color="primary">
<ion-title>Hi</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item [routerLink]="['/orders']" routerLinkActive="active" (click)="close()" >My Orders</ion-item>
<ion-item [routerLink]="['/apps']" routerLinkActive="active" (click)="close()">My</ion-item>
<ion-item [routerLink]="['/pres']" routerLinkActive="active" (click)="close()">My</ion-item>
<ion-item>{{ (item | async)?.name }}</ion-item>
</ion-list>
<li class="text" *ngFor="let item of items | async">
{{ item | json }}
</li>
</ion-content>
</ion-menu>
<ion-router-outlet main></ion-router-outlet>
</ion-app>
This is my app.module.ts file
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { RouteReuseStrategy } from '#angular/router';
import { FormsModule } from '#angular/forms';
import { IonicModule, IonicRouteStrategy } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { AngularFireModule } from '#angular/fire';
import { environment } from '../environments/environment';
import { AngularFirestoreModule } from '#angular/fire/firestore';
import { AngularFireDatabaseModule } from '#angular/fire/database';
import { AngularFireAuthModule } from '#angular/fire/auth';
#NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [BrowserModule, FormsModule, IonicModule.forRoot(), AppRoutingModule, AngularFireModule.initializeApp(environment.firebase), AngularFireDatabaseModule, AngularFireAuthModule],
providers: [
StatusBar,
GooglePlus,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
})
export class AppModule {}
Image of my Firebase database. This is what can be seen right underneath my app name: https://pasteboard.co/HTxY5eC.png
Hi Kiran and welcome to SO. You went way overkill on how much information you provided, but rather be safe than sorry - right?
In the example you're looking at item is the node in the database. I take it you're also fairly new to Firebase, so I won't assume anything.... Have you played around with the Firebase console yet? (https://console.firebase.google.com/project/PROJECT_NAME/database/PROJECT_NAME/data) The view that allows you to see the contents of your Real-Time Database? Play around in there and add a few "nodes" in the database. They have nicely coordinated colors for when you add, edit, and remove data... pretty cool, right? Now erase your test nodes and create a node named "item", and add a few child nodes.
In your code this.item = db.object('item').valueChanges(); listens to the changes in the information stored in the item node of your database... and sticks it into the this.item variable. Your HTML file loops over any contents of the this.item variable and displays it via *ngFor="let item of items | async
So long story short - your original question... item isn't anything special - make it whatever you call your database node. You're getting null because right now you are missing a node in your DB with a matching name of item
I am trying to change from a home page (ie localhost.com) to a another page (localhost.com/listing). The app builds properly but when I try to change the page, nothing happens.
I have followed mainly the tutorial, https://www.youtube.com/watch?v=L6ipgij-AUw.
Here is my full app.module.ts file:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { ListingsComponent } from './listings/listings.component';
#NgModule({
declarations: [
AppComponent,
ListingsComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
RouterModule.forRoot([
{
path: 'listing',
component: ListingsComponent
}
])
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
btnClick = function () {
this.router.navigate('/listing');
};
}
I am not sure whether the btnClick function is in the right place. I got the partial solution of this Q&A board but not sure its in the correct position. I have checked the listings component is working correctly by using . It says "listings works!" but still does so from the same home page (ideally this should be a blank white page with "listings works!", eg no nav-bar).
How should I route to a new page properly (ie no trace of the home page in /listing)? I cannot understand why this is happening because the listings.component.html does not include anything from the homepage.
For more information see: https://github.com/gf1721/directoryapp.
Depending on how large you are planning on making this application, you are better off with creating an routing module.
Step 1:
This will generate an app-routing module for you in your src/app folder.
ng g m app-routing
Step 2:
Open your app-routing module and import all of the components you want to be able to navigate too as well as routermodule and routes.
import { RouterModule, Routes } from '#angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';
import { HomeComponent } from './home/home.component';
import { LoginComponent } from './login/login.component';
Step: 3
Add a constant with the routes setup:
const routes: Routes = [
{path: '', redirectTo: 'home', pathMatch: 'full'},
{path: 'home', component: HomeComponent},
{path: 'dashboard', component: DashboardComponent},
{path: 'login', component: LoginComponent},
];
Step 4
Add your routes to your imports and then export the router module:
#NgModule({
imports: [
CommonModule,
RouterModule.forRoot(routes)
],
exports: [RouterModule],
declarations: []
})
Step 5
Now in your template html file you can do the follow:
<button type="button" routerLink="/home">Go home</button>
<router-outlet></router-outlet>
And the content on "home" will appear where router-outlet is.
Change
From
btnClick = function () {
this.router.navigate('/listing');
};
To
btnClick () : void {
this.router.navigate('/listing');
}
Also the button should be on the component, you are placing it inside the module, which will anyway not work.
Place the button on the app component and bind the logic to navigate on the button click as mentioned above
I want to have an sidebar that can display the name of the user who logged in. I have an account page that display all the details of the user. This is the code of the typescript below for the accounts page.
import { Component } from '#angular/core';
import { NavController, AlertController} from 'ionic-angular';
import {Headers} from "#angular/http";
import 'rxjs/add/operator/map';
import {Storage} from "#ionic/storage";
import { Global } from '../../providers/global';
#Component({
selector: 'page-account',
templateUrl: 'account.html',
})
export class AccountPage {
constructor(public navCtrl: NavController,
private storage: Storage,
public alertCtrl: AlertController,
public global: Global
)
{
//
}
public ACCOUNT_URL = this.global.url + "/api/inspectors";
credentials:any;
contentHeader = new Headers({"Content-Type": "application/json"});
error: any;
user: any;
token_type: any;
access_token: any;
refresh_token:any;
ionViewDidLoad() {
console.log('ionViewDidLoad AccountPage');
this.getAccessToken();
this.getAccount();
}
getAccessToken(){
this.storage.get('access_token').then((value) => {
this.access_token=value;
});
}
getAccount(){
this.storage.get('user').then((value) => {
this.user=value;
});
}
}
and this is the code in my html.
<ion-header>
<ion-navbar color="danger">
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Account</ion-title>
</ion-navbar>
</ion-header>
<ion-content class="page-account">
<ion-card>
<ion-item *ngIf="user">
<ion-card-content text-wrap>
<h2>Name: {{user.name}}</h2>
<p>{{user.cellphone_no}}</p>
<p> Address: {{user.address}} </p>
<p> Email: {{user.email}} </p>
</ion-card-content>
</ion-item>
</ion-card>
</ion-content>
What I want to happen is to delete the account pages and put the details of the user in top of the sidebar. So I have to put it into the app.html or app.ts but how can I define the property in my root component in order to display the details of that user.
Here is the code below in my app.component.ts
import { Component, ViewChild} from '#angular/core';
import { Nav, Platform } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import {Storage} from "#ionic/storage";
import { LoginPage } from '../pages/login/login';
import { AccountPage } from '../pages/account/account';
import { InspectionPage } from '../pages/inspection/inspection';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = LoginPage;
#ViewChild(Nav) nav: Nav;
pages: Array<{title: string, component: any, icon: string, color: string}>;
constructor(platform: Platform,
statusBar: StatusBar,
private storage: Storage,
splashScreen: SplashScreen) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
statusBar.styleDefault();
splashScreen.hide();
});
// used for an example of ngFor and navigation
this.pages = [
//{ title: 'Home', component: HomePage, icon: 'home', color: 'primary' },
{ title: 'Home', component: InspectionPage, icon: 'home', color: 'danger' },
{ title: 'Account', component: AccountPage, icon: 'person', color: 'primary' }
];
}
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.setRoot(page.component);
}
logout() {
// Reset the content nav to have just this page
// we wouldn't want the back button to show in this scenario
this.storage.remove('access_token');
this.storage.remove('username');
this.storage.remove('data');
this.storage.remove('user');
this.nav.setRoot(LoginPage);
}
}
and here is the code in my sidemenu or html.
<ion-menu [content]="content" id="myMenu">
<ion-header>
<ion-toolbar color="danger">
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<button menuClose ion-item *ngFor="let p of pages" (click)="openPage(p)">
<ion-icon [name]="p.icon" [color]="p.color" item-left></ion-icon> {{p.title}}
</button>
<button menuClose ion-item (click)="logout()">
<ion-icon name="log-out" color="default" item-left></ion-icon> Logout
</button>
</ion-list>
</ion-content>
</ion-menu>
<!-- Disable swipe-to-go-back because it's poor UX to combine STGB with side menus -->
<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>
What I want to happen is to put the details of the user in the sidebar like what I did in the account page. Sorry for my long question. I tried searching for it but can't find any answer to it.
Looking for help.
Thanks in advance.
I would recommend that you create a service to handle the state of the user login. That way the state is handled in a central place and it will be much easier to maintain.
One possible approach would be to use a BehaviourSubject inside your service, which you can then subscribe to on every page that you need your user object (like your account page and your app component).
import {Injectable} from '#angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
#Injectable()
export class UserService {
// Observable user object (replace any with your user class/interface)
private _userObject = new BehaviorSubject<any>({});
// Expose an observable that can be used by components
userObject$ = this._userObject.asObservable();
// Method to update the user
changeUser(user) {
this._userObject.next(user);
}
}
You can now use the service like that (you have to implement the subscription logic in every component where you want to have access to your user):
import {Component} from '#angular/core';
import {UserService} from './user.service';
#Component({
selector: 'account-page'
})
export class AccountPage {
user: any;
subscription: Subscription;
constructor(private _userService: UserService) {}
ngOnInit() {
this.subscription = this._userService.userObject$
.subscribe(item => this.user = item);
}
ngOnDestroy() {
// prevent memory leak when component is destroyed
this.subscription.unsubscribe();
}
login() {
this._userService.changeUser({
name: 'Name' // Replace with name / user object
});
}
logout() {
this._userService.changeUser({});
}
}
As mentioned above, the big advantage is maintainability. If you ever change your user object, it only requires minimal changes, whereas the solution by #Tomislav Stankovic requires changes in every component where the user is used.
In your login page, when user is successfully logged-in, store data to localStorage
login(username,password){
this._api.userLogin().subscribe(res => {
if(res.status == 'ok'){
localStorage.setItem('user_first_name', res.user_first_name);
localStorage.setItem('user_last_name', res.user_last_name);
}
}
And then in app.component.ts get data from localStorage
this.first_name = localStorage.getItem('user_first_name');
this.last_name = localStorage.getItem('user_last_name');
Display data in app.html
<p>{{first_name}}</p>
<p>{{last_name}}</p>
On log-out clear localStorage
logout(){
localStorage.clear();
}
I start my project with tabs template and then I add side menu into it. Both tabs and side menu work, but if i click on menu item, page lost tabs view.
app.components.ts
#Component({
templateUrl: 'app.html'
})
export class MyApp {
#ViewChild(Nav) nav: Nav;
rootPage = TabsPage;
pages: Array<{title: string, component: any}>;
constructor(public platform: Platform) {
this.initializeApp();
// used for an example of ngFor and navigation
this.pages = [
{ title: 'Home', component: HomePage },
{ title: 'About', component: AboutPage },
{ title: 'Contact', component: ContactPage }
];
}
initializeApp() {
this.platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
Splashscreen.hide();
});
}
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.setRoot(page.component);
}
app.html
<ion-menu [content]="content" push persistent=true>
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="outer-content">
<ion-list>
<button menuClose ion-item *ngFor="let p of pages" (click)="openPage(p)">
{{p.title}}
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>
The issue is you are setting the component selected from the menu as root.
this.nav.setRoot(page.component);
This replaces the existing TabsPage with the selected page as root rather than change the selected tab of the TabsPage.
A solution is to send the page object from openPage() function to TabsPage using Events API or a service with Observable/Subject.
openPage(page) {
this.events.publish('menu selected',page);
}
In your TabsPage,
ngOnInit(){
this.events.subscribe('menu selected',this.openPage.bind(this))
}
openPage(page){
this.tabs.select(page.index);//set an additional property with index same as tab order.
}