How to pass data between tabs in Ionic

2020-06-18 09:48发布

问题:

I have a simple project with 3 tabs. When the user hits a button on an item on the first tab I need that item to move to the second tab and vise versa. (I also need to notify a server when this happens). Is there any way for me to pass a item object to a array in the About-Page tab and vise versa?

home.html

<ion-header>
  <ion-toolbar>
    <ion-title>Home</ion-title>
    <ion-buttons end>
      <button ion-button icon-only color="royal" (click)="updateData()">
        <ion-icon name="refresh"></ion-icon>
      </button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>

<ion-content>
  <ion-list>
    <ion-item-sliding *ngFor="let item of items">
      <ion-item>
        <ion-icon name="alert" *ngIf="!item.taken" item-left></ion-icon>
        <ion-icon name="checkmark-circle-outline" *ngIf="item.taken" item-left></ion-icon>
        <h2><b>{{item.title}}</b></h2>
        <h3>{{item.name}} | {{item.number}}</h3>
        <h3 style="white-space: normal;"><b>Details:</b> {{item.text}}</h3>
      </ion-item>
      <ion-item-options side="left">
        <button ion-button color="primary" (click)="smsPressed(item)">
          <ion-icon name="text"></ion-icon>
          Text
        </button>
        <button ion-button color="secondary" (click)="phonePressed(item)">
          <ion-icon name="call"></ion-icon>
          Call
        </button>
      </ion-item-options>
      <ion-item-options side="right">
        <button ion-button color="primary" *ngIf="item.taken" (click)="responderPressed(item)">
          <ion-icon name="person"></ion-icon>
          Responder
        </button>
        <button ion-button color="primary" *ngIf="!item.taken" (click)="takecallPressed(item)">
          <ion-icon name="navigate"></ion-icon>
          Take Call
        </button>
      </ion-item-options>
    </ion-item-sliding>
  </ion-list>

  <ion-fab right bottom>
    <button ion-fab color="light" (click)="addItem()"><ion-icon name="add"></ion-icon></button>
  </ion-fab>
</ion-content>

home.ts

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { AlertController } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  items: any[];

  constructor(public navCtrl: NavController, public alertCtrl: AlertController) {
    this.items = []
      this.items.push({
        title: "Title",
        text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pretium quam at est porta fringilla.",
        name: "Sam",
        number: "(555) 555-5555",
        taken: true,
        responder: {
          name: "Bob",
          phone: "(666) 666-6666"
        }
      })
      this.items.push({
        title: "Stuff",
        text: "Take Now",
        name: "Sam",
        number: "(555) 555-5555",
        taken: false,
        responder: {}
      })

  }

  buttonPressed(item){
    alert(item.title)
  }

  smsPressed(item){alert(item.number)}

  phonePressed(item){alert(item.number)}

  responderPressed(item){alert(item.responder.name)}

  takecallPressed(item){alert(item.taken)}

  updateData(){
    this.items.unshift({
      title: "Added",
      text: "Take Now",
      name: "Sam",
      number: "(555) 555-5555",
      taken: false,
      responder: {}
    })
  }

  addItem(){
    let prompt = this.alertCtrl.create({
      title: 'Add Call',
      message: "Enter the details for the call you want to add",
      inputs: [
        { name: 'title',  placeholder: 'Title'},
        { name: 'text',  placeholder: 'Details'},
        { name: 'name',  placeholder: 'Name'},
        { name: 'number',  placeholder: 'Number'},
      ],
      buttons: [
        { text: 'Cancel',handler: data => {}},
        { text: 'Save',handler: data => {
            this.items.unshift({
              title: data.title,text: data.text,
              name: data.name,number: data.number,
              taken: false,responder: {}
            })
          }
        }
      ]
    });
    prompt.present();
  }
}

tabs.html

<ion-tabs>
      <ion-tab [root]="tab1Root" tabTitle="Home" tabIcon="home"></ion-tab>
      <ion-tab [root]="tab2Root" tabTitle="Current" tabIcon="alarm"></ion-tab>
      <ion-tab [root]="tab3Root" tabTitle="Account" tabIcon="contacts"></ion-tab>
</ion-tabs>

tabs.ts

import { Component } from '@angular/core';
import { HomePage } from '../home/home';
import { AboutPage } from '../about/about';
import { ContactPage } from '../contact/contact';

@Component({
  templateUrl: 'tabs.html'
})
export class TabsPage {
  // this tells the tabs component which Pages
  // should be each tab's root Page
  tab1Root: any = HomePage;
  tab2Root: any = AboutPage;
  tab3Root: any = ContactPage;

  constructor() {

  }
}

回答1:

There are several way you could achieve this.

  1. Events would be the right choice when it comes to passing data between different pages.

    Events is a publish-subscribe style event system for sending and responding to application-level events across your app.

    create an event with

    constructor(public events: Events) {}
    function sendData(data) {
      events.publish('data:created', data);
    }
    

    subscribe to it using

    events.subscribe('data:created', (data) => { console.log( data); });


  1. Use a shared service

    constructor(public shared: Share) {} pushData(data){ this.shared.items.push(data); }

    You can access items in other components using this.shared.items when you inject the service globally in app.module.ts


  1. Another option would be to use segments instead of tabs. This depends on the use case. For simple applications, this would be the better solution. You can learn more from the documentation.

Edit

I have avoided storing the data in database as its not an efficient way to do this. But there may be use cases for such an approach.



回答2:

LocalStorage - This could be one of the ways you can solve it.

You can store the necessary data in your localStorage after a specific action from 1 tab using -

let data = {"demo": "demo"};
localStorage.setItem('myData',JSON.stringify(data));

Now, in another tab you can use ionic's lifecycle even ionViewWillEnter() which gets executed whenever a view is entered so the data will be refreshed. Here you can access your data stored in localStorage like this:

ionViewWillEnter(){
    let data = JSON.parse(localStorage.getItem('myData'));
    console.log("Did data load? : ",data);
}

NOTE : You need to use JSON.stringify() and JSON.parse() while storing and retrieving from localStorage as you can only store strings in it.



回答3:

I know, old thread, and Observables/Events is a good way to do it,

but in Ionic, tabs are yet another ion-router-outlet for each tab. So you already have ActivatedRoute. You might think the ActivatedRoute inside your tab component is just for that specific ion-router-outlet, and that it will not contain the same data your tabs.ts has, but you can access the parent ActivatedRoute.

This is where resolvers are storing their resolved data.

in your tabs.ts just populate this value (either using resolvers or ion-refresher or otherwise)

this.activatedRoute.snapshot.data['yourData'];

And in each of your tabs components you can access it by:

this.activatedRoute.snapshot.parent.data['yourData'];

Don't forget to inject the ActivatedRoute object in your constructor.

Also, be aware this is a solution for ionic 4/5, I don't know if it works for 3 and earlier.