I have tabs module with the following structure/code:
tabs.router.module.ts:
const routes: Routes = [
{
path: '',
component: TabsPage,
children: [
{
path: '',
outlet: 'home',
component: HomePage
},
{
path: 'chats',
component: ChatsPage,
outlet: 'chats'
},
{
path: 'notifications',
component: NotificationsPage,
outlet: 'notifications',
}
]
}
];
tabs.html
<ion-tabs>
<ion-tab label="HOME" icon="list-box" href="">
<ion-router-outlet stack name="home"></ion-router-outlet>
</ion-tab>
<ion-tab label="CHATS" icon="list-box" href="chats">
<ion-router-outlet stack name="chats"></ion-router-outlet>
</ion-tab>
<ion-tab label="NOTES" icon="list-box" href="notifications">
<ion-router-outlet stack name="notifications"></ion-router-outlet>
</ion-tab>
</ion-tabs>
When I click chats - I get:
ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'notifications'
Error: Cannot match any routes. URL Segment: 'notifications'
why?
try adding this to your routs also
{
path: '',
redirectTo: '/tabs/(home:home)',
pathMatch: 'full',
},
this is the html code
<ion-tabs>
<ion-tab label="HOME" icon="list-box" href="/tabs/(home:home)">
<ion-router-outlet stack name="home"></ion-router-outlet>
</ion-tab>
<ion-tab label="CHATS" icon="list-box" href="/tabs/(chats:chats)">
<ion-router-outlet stack name="chats"></ion-router-outlet>
</ion-tab>
<ion-tab label="NOTES" icon="list-box" href="/tabs/(notifications:notifications)">
<ion-router-outlet stack name="notifications"></ion-router-outlet>
</ion-tab>
</ion-tabs>
Router:
const routes: Routes = [
{
path: 'tabs',
component: TabsPage,
children: [
{
path: 'home',
outlet: 'home',
component: HomePage
},
{
path: 'chats',
component: ChatsPage,
outlet: 'chats'
},
{
path: 'notifications',
component: NotificationsPage,
outlet: 'notifications',
}
]
},{
path: '',
redirectTo: '/tabs/(home:home)'
}
];
Template:
<ion-tabs>
<ion-tab label="HOME" icon="list-box" href="/tabs/(home:home)">
<ion-router-outlet stack name="home"></ion-router-outlet>
</ion-tab>
<ion-tab label="CHATS" icon="list-box" href="/tabs/(chats:chats)">
<ion-router-outlet stack name="chats"></ion-router-outlet>
</ion-tab>
<ion-tab label="NOTES" icon="list-box" href="/tabs/(notifications:notifications)">
<ion-router-outlet stack name="notifications"></ion-router-outlet>
</ion-tab>
</ion-tabs>
Related
I'm having this weird problem, I have started a new app with Tabs and angular routing.
I have added a new Login page, and after login, the user is redirected to the tabs page.
The problem is that after the redirect, sometimes only one tab is rendered, and sometimes two tabs are rendered.
If I refresh the page or go directly to it, all 3 tabs are shown.
If I start the app on the Tabs page, again, all 3 tabs are shown.
AppRoutingModule:
const routes: Routes = [
{path: 'login', loadChildren: './login/login.module#LoginPageModule'},
{path: 'home', loadChildren: './tabs/tabs.module#TabsPageModule'},
{path: '', redirectTo: '/login', pathMatch: 'full'}];
TabsPageRoutingModule:
const routes: Routes = [
{
path: '',
component: TabsPage,
children: [
{
path: 'home',
outlet: 'home',
component: HomePage
},
{
path: 'about',
outlet: 'about',
component: AboutPage
},
{
path: 'contact',
outlet: 'contact',
component: ContactPage
}
]
},
{
path: '',
redirectTo: '/tabs/(home:home)',
pathMatch: 'full'
}];
LoginPage:
export class LoginPage implements OnInit {
responseData: any;
userData = {'email': '', 'password': ''};
constructor(public navCtrl: NavController, public apiService: ApiService, public toastCtrl: ToastController) {
}
login() {
this.apiService.login(this.userData).then((result) => {
this.responseData = result;
if (this.responseData.token) {
console.log(this.responseData);
localStorage.setItem('token', this.responseData.token);
this.navCtrl.goRoot('/home');
} else {
console.log('User already exists');
}
}, (err) => {
// Error log
console.log(err);
});
}
ngOnInit() {
}}
Any Ideas? Thanks!
As of today, November 1, 2018 the tabs in Ionic 4 (4.0.0-beta.15) have been completely changed.
https://github.com/ionic-team/ionic/blob/master/CHANGELOG.md#400-beta15-2018-11-01
Basically, they've updated the tabs to be a tab-bar of buttons that can be used to load ion-router-outlet, ion-content or ion-nav components.
Some other benefits of this refactor include:
Can now be written as a standalone Tab Bar (with no attached Tab)
Works with a navigation component or a plain content element
Works with shadow DOM and allows easy customization of the Tab Bar
Gives full control over the elements inside of the Tab Bar
Integrates nicely with other frameworks that have different ways of rendering element nodes
Try changing
this.navCtrl.goRoot('/home');
to
this.navCtrl.goRoot('/tabs'); to
step 1:
const routes: Routes = [
{
path: 'tabs',
component: TabsPage,
children: [
{
path: 'home',
outlet: 'home',
component: HomePage
},
{
path: 'about',
outlet: 'about',
component: AboutPage
},
{
path: 'contact',
outlet: 'contact',
component: ContactPage
}
]
},
{
path: '',
redirectTo: '/home/tabs/(home:home)',
pathMatch: 'full'
}];
step 2:
this.navCtrl.goRoot('/home');
I had the same problem.
After reviewing my HTML I realized that I had a problem, in the "ion-tab" the input "label" its empty and this caused the problem, the error:
<ion-tab label="" icon="medkit" href="/(entidades:entidades)">
<ion-router-outlet name="entidades">
</ion-router-outlet>
</ion-tab>
the solution for me:
<ion-tab label="The label of tab" icon="medkit" href="/(entidades:entidades)">
<ion-router-outlet name="entidades">
</ion-router-outlet>
</ion-tab>
I hope it helps you
The issue I am having is that when I use these both together, Tab navigation dissapears when using side menu navigation.
Using tab navigation makes the app work similar to a SPA i'm assuming, in that the page is loaded in the view. However, when I navigate using the side menu, I go directly to that page, which is circumventing the point of the tab navigation.
Is there a way to make these both work together?
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 { HomePage } from '../pages/home/home';
import { Settings } from '../pages/settings/settings';
import { Journeys } from '../pages/journeys/journeys';
import { TabsPage } from '../pages/tabs/tabs';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
#ViewChild(Nav) nav: Nav;
rootPage: any = TabsPage;
pages: Array<{title: string, component: any}>;
constructor(public platform: Platform, public statusBar: StatusBar,
public splashScreen: SplashScreen) {
this.initializeApp();
this.pages = [
{ title: 'Home', component: HomePage },
{ title: 'Settings', component: Settings },
{ title: 'Journeys', component: Journeys }
];
}
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleDefault();
this.splashScreen.hide();
});
}
openPage(page) {
this.nav.setRoot(page.component);
}
}
app.html:
<ion-menu [content]="content">
<ion-header>
<ion-toolbar>
<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)">
{{p.title}}
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>
Tabs.ts:
import { Component } from '#angular/core';
import { HomePage } from '../home/home';
import { Journeys } from '../journeys/journeys';
import { Settings } from '../settings/settings';
#Component({
templateUrl: 'tabs.html'
})
export class TabsPage {
tab1Root = HomePage;
tab2Root = Journeys;
tab3Root = Settings;
constructor() {
}
}
Tabs.html:
<ion-tabs>
<ion-tab [root]="tab1Root" tabTitle='Home' tabIcon='ios-home'></ion-tab>
<ion-tab [root]="tab2Root" tabTitle='Journeys' tabIcon='ios-car'></ion-tab>
<ion-tab [root]="tab3Root" tabTitle='Settings' tabIcon='md-settings'></ion-tab>
homepage.html:
<ion-header>
<ion-navbar>
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Home</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-grid>
<ion-row>
<ion-col col-12>
<p class='homepage_placeholder'>Homepage Placeholder</p>
</ion-col>
</ion-row>
</ion-grid>
</ion-content>
Firstly, add tabIndex to your this.pages
this.pages = [
{ title: 'Home', component: HomePage, tabIndex:0 },
{ title: 'Settings', component: Settings, tabIndex:1 },
{ title: 'Journeys', component: Journeys, tabIndex:2 }
{ title: 'PageNotInTab', component: componentName }
];
And then, make your openPage() like this
openPage(page): void{
if(page.tabIndex){
this.nav.setRoot(TabsPage,{selectedIndex:page.tabIndex})
}else{
this.nav.setRoot(page.component,{})
}
}
Of cousre, TabsPage should be prepared before implementing the code above.
I leave out the details.
In TabsPage
ngAfterContentInit(){
if(this.navParams.data.hasOwnProperty("selectedIndex"))
this._selectedIndex = this.navParams.get("selectedIndex")
else
this._selectedIndex=0;
}
I want when I clicked feedback button can go feedback page, but after I set up all, after clicked still showing tabsPage.
app.component.ts
appPages: PageInterface[] = [
{ title: '新闻', name: 'TabsPage', component: TabsPage, index: 0, icon: 'ios-globe-outline' },
{ title: 'SOS', name: 'TabsPage', component: TabsPage, index: 1, icon: 'call' },
{ title: '服务', name: 'TabsPage', component: TabsPage, index: 2, icon: 'people' },
{ title: '反馈', name: 'FeedbackPage', component: FeedbackPage, icon: 'contacts' }
];
loggedInPages: PageInterface[] = [
{ title: '新闻', name: 'TabsPage', component: TabsPage, index: 0, icon: 'ios-globe-outline' },
{ title: 'SOS', name: 'TabsPage', component: TabsPage, index: 1, icon: 'call' },
{ title: '服务', name: 'TabsPage', component: TabsPage, index: 2, icon: 'people' },
{ title: '反馈', name: 'FeedbackPage', component: FeedbackPage, icon: 'contacts' },
{ title: '注销', name: 'TabsPage', component: TabsPage, icon: 'log-out', logsOut: true }
];
The last one is the feedback button, when I click feedback button just back to tabsPage not go into feedback page.
UPDATE:
I am checking this code in app.components.ts
openPage(page: PageInterface) {
let params = {};
if (page.index) {
params = { tabIndex: page.index };
}
if (this.nav.getActiveChildNavs().length && page.index != undefined) {
this.nav.getActiveChildNavs()[0].select(page.index);
} else {
// Set the root of the nav with params if it's a tab index
this.nav.setRoot(page.name, params).catch((err: any) => {
console.log(`Didn't set nav root: ${err}`);
});
}
if (page.logsOut === true) {
// Give the menu time to close before changing to logged out
this.userData.logout();
}
}
Is it need to change params?
app.html
<ion-menu id="loggedOutMenu" [content]="content">
<ion-header>
<ion-toolbar color="danger">
<ion-title>菜单</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-list-header>请登录</ion-list-header>
<button color="wechat" style="width:40%" ion-button clear (click)= "wechatLogin()">
<ion-icon name="minan-login-wechat"></ion-icon>
</button>
<button color="facebook" style="width:40%" ion-button clear (click)= "FBLogin()">
<ion-icon name="minan-login-facebook"></ion-icon>
</button>
<ion-list-header>导航栏</ion-list-header>
<button menuClose ion-item *ngFor="let p of appPages" (click)="openPage(p)">
<ion-icon item-start [name]="p.icon" [color]="isActive(p)"></ion-icon>
{{p.title}}
</button>
</ion-list>
</ion-content>
</ion-menu>
Feedback page doesn't have own module because I am using 'ionic generate page Feedback --no-module' to generate my Feedback page
This means you are not using lazy loading and the page is not an IonicPage.
#IonicPage()
which sets the name property as the component name by default.
This will automatically create a link to the MyPage component using the same name as the class, name: 'MyPage'. The page can now be navigated to by using this name.
And also you dont have PageModule
In your case, you will have to set the imported component/page and not the string with your NavController functions.
Do:
this.nav.setRoot(page.component, params).catch((err: any) => {
console.log(`Didn't set nav root: ${err}`);
});//page.component
Based on your app structure, you app might be based on ionic conference starter template, what iv'e done is remove extra parameters in IonicModule.forRoot(ConferenceApp), like links array and extra objects, then do the lazy loading for your pages by Adding and importing an #IonicPage() on your components.
Before:
IonicModule.forRoot(ConferenceApp, {}, {
links: [
{ component: TabsPage, name: 'TabsPage', segment: 'tabs-page' },
{ component: SchedulePage, name: 'Schedule', segment: 'schedule' },
{ component: SessionDetailPage, name: 'SessionDetail', segment: 'sessionDetail/:sessionId' },
{ component: ScheduleFilterPage, name: 'ScheduleFilter', segment: 'scheduleFilter' },
{ component: SpeakerListPage, name: 'SpeakerList', segment: 'speakerList' },
{ component: SpeakerDetailPage, name: 'SpeakerDetail', segment: 'speakerDetail/:speakerId' },
{ component: MapPage, name: 'Map', segment: 'map' },
{ component: AboutPage, name: 'About', segment: 'about' },
{ component: TutorialPage, name: 'Tutorial', segment: 'tutorial' },
{ component: SupportPage, name: 'SupportPage', segment: 'support' },
{ component: AccountPage, name: 'AccountPage', segment: 'account' },
{ component: SignupPage, name: 'SignupPage', segment: 'signup' }
]
After:
IonicModule.forRoot(ConferenceApp),
login.module.ts
import { NgModule } from '#angular/core';
import { IonicPageModule } from 'ionic-angular';
import { LoginPage } from './login';
#NgModule({
declarations: [
LoginPage,
],
imports: [
IonicPageModule.forChild(LoginPage),
],
})
export class RequestTrainingPageModule {}
login.ts
import { Component } from '#angular/core';
import { NgForm } from '#angular/forms';
import { IonicPage, NavController } from 'ionic-angular';
import { UserOptions } from '../../interfaces/user-options';
import { UserData } from '../../providers/user-data';
import { TabsPage } from '../tabs-page/tabs-page';
#IonicPage()
#Component({
selector: 'page-user',
templateUrl: 'login.html'
})
export class LoginPage {
login: UserOptions = { username: '', password: '' };
submitted = false;
constructor(public navCtrl: NavController, public userData: UserData) { }
onLogin(form: NgForm) {
this.submitted = true;
if (form.valid) {
this.userData.login(this.login.username);
this.navCtrl.push(TabsPage);
}
}
onSignup() {
this.navCtrl.push('SignupPage');
}
}
I need to hide one of loggedInPages items in Ionic Conference App
For example I have an admin Page. When user logged in application, user can see admin page link in loggedInPages if user's role is admin .
loggedInPages: PageInterface[] = [
{ title: 'Account', name: 'AccountPage', component: AccountPage, icon: 'person' },
{ title: 'Support', name: 'SupportPage', component: SupportPage, icon: 'help' },
{ title: 'Logout', name: 'TabsPage', component: TabsPage, icon: 'log-out', logsOut: true },
{ title: 'Admin', name: 'Admin', component: AdminPage, icon: 'unlock'}
];
<ion-list>
<ion-list-header>
Account
</ion-list-header>
<button ion-item menuClose *ngFor="let p of loggedInPages" (click)="openPage(p)">
<ion-icon item-start [name]="p.icon" [color]="isActive(p)"></ion-icon>
{{p.title}}
</button>
</ion-list>
Instead of using loggedInPages field as it is in ngFor loop, you can create a function like getLoggedInPagesAsPerUserRole() which will return only the pages according to the role of the logged in user.
I am building my first hybrid app with Ionic, and there is something I do not understand.
What is the use of ion-nav-view.
I explain: I have an app with "nav-tabs". Here is the code of a nav-tab:
<ion-tab title="Contacts" icon="icon-users" href="#/tab/contacts">
<ion-nav-view name="tab-contacts"></ion-nav-view>
</ion-tab>
Everything is OK here.
So now, my list of contacts is a list which goes like this:
<ion-item href="#/tab/contacts/{{contact.id}}" ng-repeat="contact in contacts | orderBy:'name'">
{{contact.name}}
</ion-item>
Here is my problem: I have configured a route for '/tab/contacts/:id', and a view. The problem is: where should I put the equivalent of the "ion-nav-view" directive, so that my view is actually shown when I click?
Thank you!
I think the best answer is a working example similar to what you want to do.
However <ion-nav-view> must be in your index.html and it is where the route/state manager will put the templates of your views. The templates have another directive, <ion-view>, which wraps all other directives and content of the view.
Check the snippet below:
angular.module('ionicApp', ['ionic'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('tabs', {
url: '/tab',
abstract: true,
templateUrl: 'views/tabs.html'
})
.state('tabs.contacts', {
url: '/contacts',
views: {
'tab-contacts': {
templateUrl: 'views/contacts.html',
controller: 'contactsCtrl',
resolve: {
allcontacts: function(Contacts) {
console.log("resolve allcontacts");
return Contacts.all();
}
}
}
}
})
.state('tabs.detail', {
url: '/detail/:id',
views: {
'tab-detail': {
templateUrl: 'views/detail.html',
controller: 'detailCtrl',
resolve: {
contact: function($stateParams, Contacts) {
return Contacts.get($stateParams.id);
}
}
}
}
});
$urlRouterProvider.otherwise("/tab/contacts");
})
.controller('contactsCtrl', function($scope, $ionicLoading, $ionicPopover, $ionicPopup, $compile, $http, allcontacts) {
console.log("contactsCtrl");
$scope.contacts = allcontacts;
})
.controller('detailCtrl', function($scope, contact, $ionicHistory) {
$scope.contact = contact;
console.log("detailCtrl", contact);
$scope.myGoBack = function() {
$ionicHistory.goBack();
};
})
.factory('Gravatar', function() {
return {
getUrl: function(s){
return "https://secure.gravatar.com/avatar/"+CryptoJS.MD5(""+Math.random())+"?d=identicon&s="+s;
}
}
})
.factory('Contacts', function($http, $q, $timeout, Gravatar) {
var contacts = [];
return {
all: function(){
var dfd = $q.defer();
//$http.get('../data/contacts.json').then(function(response){
$timeout(function() {
//contacts = response.data;
contacts = [{
id: 1,
name: "William",
surname: "Hayes",
fullname: "Grace Beatty",
image: Gravatar.getUrl(128)
}, {
id: 2,
name: "James",
surname: "Jennings",
fullname: "Hilda Gross",
image: Gravatar.getUrl(128)
}, {
id: 3,
name: "Judith",
surname: "Silverman",
fullname: "Bruce Kern",
image: Gravatar.getUrl(128)
}, {
id: 4,
name: "Greg",
surname: "Fitzpatrick",
fullname: "Heather Bowers",
image: Gravatar.getUrl(128)
}, {
id: 5,
name: "Teresa",
surname: "McLean",
fullname: "Leon Baker",
image: Gravatar.getUrl(128)
}, {
id: 6,
name: "Emily",
surname: "Lassiter",
fullname: "Virginia Pittman",
image: Gravatar.getUrl(128)
}, {
id: 7,
name: "Don",
surname: "Sinclair",
fullname: "Ashley Richards",
image: Gravatar.getUrl(128)
}, {
id: 8,
name: "Hazel",
surname: "Livingston",
fullname: "Gloria O",
image: Gravatar.getUrl(128)
}, {
id: 9,
name: "Regina",
surname: "Braun",
fullname: "Monica Casey",
image: Gravatar.getUrl(128)
}, {
id: 10,
name: "Leroy",
surname: "Pritchard",
fullname: "Gretchen Sharpe",
image: Gravatar.getUrl(128)
}];
//console.log(contacts);
dfd.resolve(contacts);
console.log("contacts.all");
});
return dfd.promise;
},
get: function(id) {
for (var i = 0; i < contacts.length; i++) {
if (contacts[i].id == id) {
return contacts[i];
}
}
return null;
}
}
});
<html ng-app="ionicApp">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title>Ionic detail view</title>
<link href="http://code.ionicframework.com/nightly/css/ionic.min.css" rel="stylesheet">
<script src="http://code.ionicframework.com/nightly/js/ionic.bundle.min.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5.js"></script>
</head>
<body>
<ion-nav-bar class="bar-positive">
<ion-nav-back-button>
</ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view></ion-nav-view>
<script id="views/tabs.html" type="text/ng-template">
<ion-tabs class="tabs-icon-top tabs-color-active-positive">
<ion-tab title="Contacts" icon-off="ion-ios-people-outline" icon-on="ion-ios-people" href="#/tab/contacts">
<ion-nav-view name="tab-contacts"></ion-nav-view>
</ion-tab>
<ion-tab title="Contact detail" icon-off="ion-ios-person-outline" icon-on="ion-ios-person href="#/tab/detail">
<ion-nav-view name="tab-detail"></ion-nav-view>
</ion-tab>
</ion-tabs>
</script>
<script id="views/contacts.html" type="text/ng-template">
<ion-view title="Contacts">
<ion-content>
<ion-list>
<ion-item class="item item-thumbnail-left" ng-repeat="contact in contacts" ui-sref="tabs.detail({ id: contact.id })">
<img ng-src="{{ contact.image }}" />
<h2>{{ contact.name }}</h2>
<p>{{ contact.fullname }}</p>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
</script>
<script id="views/detail.html" type="text/ng-template">
<ion-view title="Contact detail">
<ion-nav-buttons side="left">
<button class="button button-clear" ng-click="myGoBack()" >
<i class="icon ion-ios-arrow-back"></i>
Back</button>
</ion-nav-buttons>
<ion-content>
<ion-item class="list-item">
<img ng-src="{{ contact.image }}" alt="{{ contact.name }}" />
<div class="list-details">
<p class="sub-heading"><b>Name:</b> {{ contact.name }}</p>
<p><b>Surname:</b> {{ contact.surname }}</p>
<p><b>Fullname:</b> {{ contact.fullname }}</p>
</div>
</ion-item>
</ion-content>
</ion-view>
</script>
</body>
</html>