Ionic 2 passing tabs NavParams to tab - ionic-framework

I'm starting out on creating my first app using Ionic 2 and through a lot of trial and error have got to a point where no number of Google searching can find anything to help.
I'm trying to pass some NavParams to a tab. The NavParams are available in the parent tabs page:
#Page({
templateUrl: 'build/pages/tabs/tabs.html'
})
export class TabsPage {
constructor(params: NavParams) {
this.params = params;
console.log(this.params); // returns NavParams {data: Object}
// this tells the tabs component which Pages should be each tab's root Page
this.tab1Root = Tab1;
this.tab2Root = Tab2;
this.tab3Root = Tab3;
}
}
But I cannot seem to get the NavParams within a tab itself:
#Page({
templateUrl: 'build/pages/tab1/tab1.html'
})
export class Tab1 {
constructor(nav: NavController, params: NavParams, platform: Platform) {
this.nav = nav;
this.params = params;
this.platform = platform;
console.log(this.params); // returns NavParams {data: null}
}
}
I'm just not entirely sure how to pass the params from the tabs page to the tab itself or somehow request a param from the tab parent. I assume something like:
this.tab1Root = Tab1(this.params);
Any help would be greatly appreciated!

This question is a few weeks old so you may have already found the answer. This feature was added in February: https://github.com/driftyco/ionic/issues/5475.
Taking the code from your original tab page, let's say a parameter is passed to the "parent" tab page and we want to store it in a property called fooId (this could be an object, or just a simple integer or string value, whatever):
#Component({
templateUrl: 'tabs.html'
})
export class TabsPage {
constructor(params: NavParams) {
this.params = params;
console.log(this.params); // returns NavParams {data: Object}
this.fooId = this.params.data;
// this tells the tabs component which Pages should be each tab's root Page
this.tab1Root = Tab1;
this.tab2Root = Tab2;
this.tab3Root = Tab3;
}
}
Then in your tabs.html, you can reference it like this using the rootParams attribute (rootParams is referenced in the documenation here):
<ion-tabs>
<ion-tab tabTitle="Tab1" [root]="tab1Root" [rootParams]="fooId"></ion-tab>
<ion-tab tabTitle="Tab2" [root]="tab2Root" [rootParams]="fooId"></ion-tab>
<ion-tab tabTitle="Tab3" [root]="tab3Root" [rootParams]="fooId"></ion-tab>
</ion-tabs>
Then in your Tab1 page, you can reference your NavParams just like any other page and the value passed for foodId will be there.

For those who haven't figured out yet .....
I've searched a lot and the only answer I got was using native storage or using a service or session storage...but that wasn't what I wanted ...
So, If you have data in NavParams in Tabs.ts page and want to it pass as [rootParam] to respective Tabs...
then what you need to do is instead of assigning NavParams to a variable in Tabs.ts page what you can do is bind it directly to the [rootParams] in the HTML page.
Like ..
tabs.ts
constructor(public navParams: NavParams) { }
tabs.html
<ion-tab [root]="tab1Root" [rootParams]="navParams.get('single')" tabTitle="Customer"></ion-tab>
<ion-tab [root]="tab2Root" [rootParams]="navParams.get('second')" tabTitle="Map"></ion-tab>
Or
tabs.html
<ion-tab [root]="tab1Root" [rootParams]="navParams.data" tabTitle="Customer"></ion-tab>
tab1.ts
constructor( public navParams: NavParams) {}
ionViewDidLoad() {
console.log('ionViewDidLoad tab1Page');
console.log(this.navParams.data);
}

There is no direct way to pass Params in Tab-Pages that I know of.
I think you could play around with the NavController to make it work.
A neat workaround is to put the parameter into an injected service:
app/services/params.js:
import {Injectable} from 'angular2/core';
#Injectable()
export class Params{
constructor(){
console.log("Params()");
this.params={};
}
}
and in the controller:
import {Params} from '../../services/params'
#Page({
templateUrl: 'build/pages/home/home.html',
})
export class XYPage{
constructor(nav: NavController,platform: Platform, params: Params) {
console.log("XYPage()",this);
console.log("XYPage()", params.params);
params.params={id="001"};
dont forget to inject the service in your #App

I tried with many methods but none of them were helpful to me. As my application did not involve much of complexities, I implemented it using ionic native storage plugin. In the event that triggers the new tab page, I will store some variable in native storage(snippet is as below).
this.nativeStorage.setItem('myitem', {property: 'value', anotherProperty: 'anotherValue'})
.then(
() => console.log('Stored item!'),
error => console.error('Error storing item', error)
);
In the constructor or ionviewdidload page of the next tab page I will check for this variable and perform the required actions.Snippet is as below.
this.nativeStorage.getItem('myitem')
.then(
data => console.log(data),
error => console.error(error)
);
Note: This is suitable only for small application or where there is a requirement of passing limited set of variables. If there are lots of variable, it may take more space in the apps cache which may reduce the app performance.

tabs.html - add [rootParams]="paramName"; to the tab you want to pass data to
<ion-tabs>
<ion-tab tabTitle="Tab1" [root]="tab1Root" [rootParams]="fooId"></ion-tab>
<ion-tab tabTitle="Tab2" [root]="tab2Root"></ion-tab>
<ion-tab tabTitle="Tab3" [root]="tab3Root"></ion-tab>
</ion-tabs>
tabs.ts - set the key and data
export class TabsPage {
this.tab1Root = Tab1;
this.tab2Root = Tab2;
this.tab3Root = Tab3;
fooId: {
firstName: "lawlesscreation",
email: "user#email.com",
score: number // can also set it later in the constructor
}
constructor() {
let score = getScore(); //some method to get score
this.fooId.score = score;
}
}
tab1 page - import NavParams and use this.navParams.get(key) to get data
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
#IonicPage()
#Component({
selector: 'page-profile',
templateUrl: 'profile.html',
})
export class Tab1 {
firstName = this.navParams.get('firstName');
score = this.navParams.get('score');
userEmail = this.navParams.get('email');
constructor(public navCtrl: NavController, public navParams: NavParams) {
}
}

Related

Displaying component property from record provider is undefined

I am creating an ionic app. In this modal, I want a select with options populated from my Provider (called recordProvider). categories should hold an array of objects from the recordProvider.
The name property of these objects is what goes in the select.
I am able to log categories immediately after it is assigned from recordsProvider and it shows all the proper records perfectly. However, the next line logs the length at 0. Most importantly, the UI errors with "Cannot read property 'name' of undefined"
Why does categories have this inconsistent value?
If it is just an issue of timing and categories will have the correct data in a moment, why isn't it updated in the UI? Isn't that the whole get with Angular?
How do I fix it?
Modal ts
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams,ViewController } from 'ionic- angular';
import { RecordsProvider } from './../../providers/records/records';
#IonicPage()
#Component({
selector: 'page-add-modal',
templateUrl: 'add-modal.html',
})
export class AddModalPage {
categories:object[] = [];
constructor(public navCtrl: NavController, public navParams: NavParams, public viewCtrl : ViewController, public recordProvider: RecordsProvider) {
}
ngOnInit() {
this.categories = this.recordProvider.getAllExpenseCategories();
console.log(this.categories);
console.log(this.categories.length);
}
public closeModal(){
this.viewCtrl.dismiss();
}
}
Modal HTML
<ion-content padding>
<h1 (click)="getCat()">Hello</h1>
<p>{{categories[0].name}}</p>
<ion-item>
<ion-label>categories</ion-label>
<ion-select>
<ion-option ng-repeat="obj of categories" value="{{obj.name}}">{{obj.name}}</ion-option>
</ion-select>
</ion-item>
</ion-content>
EDIT RecordsProvider
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Storage } from '#ionic/storage';
#Injectable()
export class RecordsProvider {
getAllExpenseCategories(){
let categories = [];
this.storage.forEach( (value, key, index)=>{
if(key.indexOf("Exp") == 0){
categories.push(value);
}
});
return categories;
}
}
Ionic Storage (localForage) uses async API, so I would make sure you write your methods with it accordingly, I would re-write the getAllExpenseCategories to leverage promise which is returned by storage:
getAllExpenseCategories(){
let categories = [];
this.storage.forEach( (value, key, index)=>{
if(key.indexOf("Exp") == 0){
categories.push(value);
}
}).then(()=>{
return categories;
})
}
In your case it seems like your method was returning empty array to the component, before storage completed its forEach cycle.
Let me know if this helped

Ionic tabs loading automatically with out clicking

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

If Var on Storage dont show tabs

i want my App to check if a variable "myAccount" is on native storage to show or not Tabs, i used ionViewCanEnter to check if the variable myAccount is present on local Storage, if its not isConnected will be set to false, if its isConnected will be set to true
here's my code:
tabs.ts:
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { HomePage } from '../home/home';
import { NativeStorage } from '#ionic-native/native-storage';
import { MyaccountPage } from '../myaccount/myaccount';
/**
* Generated class for the TabsPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-tabs',
templateUrl: 'tabs.html',
})
export class TabsPage {
public isConnected: Boolean= true;
homeRoot = HomePage;
myAccountRoot = MyaccountPage;
rootPage = HomePage;
constructor(public navCtrl: NavController, public navParams: NavParams, private nativeStorage: NativeStorage) {
}
ionViewCanEnter(){
this.nativeStorage.getItem('myAccount')
.then(
//data => this.isConnected=false,
// error => this.isConnected=true
data => this.isConnected=true,
error => this.isConnected=false
);
}
logout(){
this.nativeStorage.remove('myAccount');
this.isConnected=false;
}
}
if isConnected is true it will show the tabs with HomePage as selectedIndex with the tabs visible, if its not it will show the HomePage with no Tabs
tabs.html:
<ion-tabs selectedIndex="0" *ngIf="isConnected" class="tabs-icon-top tabs-color-active-positive">
<ion-tab [root]="homeRoot" tabIcon="home"> </ion-tab>
<ion-tab [root]="myAccountRoot" tabIcon="person"></ion-tab>
<ion-tab [root]="myAccountRoot" tabIcon="chatbubbles"></ion-tab>
<ion-tab (ionSelect)="logout()" tabIcon="power"></ion-tab>
</ion-tabs>
<ion-nav [root]="rootPage" *ngIf="!isConnected">{{isConnected}}</ion-nav>
The probleme is that its not totally working, when myAccount is added to storage, the tabs doesnt show up but if i exit the application and relaunch it, they appear
used ionViewWillEnter and it worked

Ionic 3 NavController does not pop the view instead creates a new one

The ionViewDidLoad function seem to get called twice, which is causing multiple views being created of AddressPage. I have debugged this and it looks like whenever data is updated the new instance of view gets created. This behaviour seems to happen only when I use fireabse to save the address. If I comment out the code to save the address new view is not created and app navigates to previous screen.
Any way to avoid this?
I have tried ViewCotnroller.dismiss() and NavController.pop() inside saveAddress method but non seem to avoid creation of new view.
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = HomePage;
constructor(platform: Platform, statusBar: StatusBar) {
platform.ready().then(() => {
statusBar.styleDefault();
statusBar.backgroundColorByHexString('#1572b5');
});
}
}
Home Page
import {NavController } from 'ionic-angular';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController, public firebaseProvider:
FirebaseProvider) {
}
//navigate to different view
navigate(){
this.navCtrl.push(AddressPage, {address:newAddress});
}
}
Address Page
import {NavController } from 'ionic-angular';
#Component({
selector: 'page-address',
templateUrl: 'address.html'
})
export class AddressPage {
constructor(public navCtrl: NavController, public firebaseProvider:
FirebaseProvider, private navParams: NavParams) {
this.addressKey = this.navParams.get('key');
}
ionViewDidEnter(){
//load some data from server
}
saveAddress(){
//save data to server
this.firebaseProvider.saveAddress(newAddress);
//move back
this.navCtrl.pop();
}
}
Firebase provider that uses AngularFireDatabase
import { Injectable } from '#angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
#Injectable()
export class FirebaseProvider {
constructor(public afd: AngularFireDatabase) { }
saveAddress(address) {
this.afd.list('/addresses').push(address);
}
updateAddress(key,dataToUpdate){
return this.afd.list('addresses').update(key,dataToUpdate);
}
}
I have also tried this but it has the same issue.
this.firebaseProvider.saveAddress(newAddress).then(result => {
// loadingSpinner.dismiss();
this.navCtrl.pop();
});
this.firebaseProvider.updateAddress(this.addressKey, updateItems)
.then(() => {
// loadingSpinner.dismiss();
this.navCtrl.pop()
});
The HTML of save button
<button type="button" ion-button full color="primary-blue" (click)='saveAddress()'>Save</button>
Looks like unsubscribing to the subscribers fixes the issue. The HomePage view had subscribers which were not unsubscribed. I added the Observable Subscriptions into the array and unsubscribed as per code below.
ionViewWillLeave(){
this.subscriptions.forEach(item=>{
item.unsubscribe();
});
}
the push method returs a promise with the result of the action. I would change the save method like this:
saveAddress(address) {
return this.afd.list('/addresses').push(address);
}
Then in the controller I’d change it in this way:
saveAddress(){
//save data to serve
this.firebaseProvider.saveAddress(newAddress).then(result => {
//do yours validations
this.navCtrl.pop();
});
}
With thos you tide up the navigation of the page to the result of the Firebase execution. Give it a try to this approach and let me know if it didn’t work, anyway I would use oninit to load data only once as I guess you wanna do it rather than ionViewDidEnter.

force view to reload in ionic2 framework

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