Open different page on click of *ngFor loop according to data comes from provider

home.ts

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CatagoriesProvider } from '../../providers/catagories/catagories';
import { AnimalCategoriesPage } from '../animal-categories/animal-categories';
import { BodyPartsPage } from '../body-parts/body-parts'

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  catagoryList: any;
  constructor(public navCtrl: NavController, public catagories:CatagoriesProvider) {
    this.catagories.loadAll().then(result => {
      this.catagoryList = result;
    });
  }

  openPage() {
    this.navCtrl.push(AnimalCategoriesPage);
  }

}

provider.ts

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class CatagoriesProvider {
data:any;
  constructor(public http: Http) {
    this.data = [
      {catagoryName: 'Animals'},
      {catagoryName: 'Body Parts'},
      {catagoryName: 'Colors & Shapes'},
      {catagoryName: 'Apparels'},
      {catagoryName: 'Family'},
      {catagoryName: 'Vegitables & Fruits'}
    ];
  }

  loadAll() {
    return Promise.resolve(this.data);
  }
}

home.html

<ion-content padding>
  <ion-card *ngFor="let catagory of catagoryList">
    <ion-card-header text-center>
      {{catagory.catagoryName}}
    </ion-card-header>
    <ion-card-content text-center>
      <button ion-button small outline (click)="openPage(catagory)">Learn</button> <button ion-button small outline>Practice</button>
    </ion-card-content>
  </ion-card>
</ion-content>

What I would do is to add a page property to each category and use that in openPage(). If you’re lazily loading pages, it should be a string. If not, it needs to be a class name / constructor function reference.

I would also get rid of all uses of any and rename data to something more descriptive.

Since your data is an object array, shouldn’t the openPage click function look like this:

(click)="openPage(catagory.catagoryName)"

because you want to access each key of the objects you’re using.
Or just rewrite your data to be an array of your pages.

Thanks for your reply. As i am new to mobile app development, not able to follow you. Can you please elaborate or edit my code?

Thanks for your reply. I am going to add few more data in each array object so can not make that to array of strings.

Change your provider.ts to use the imported pages itself.
Then add keys to your objects (e.g. component), which represent the page component

Provider.ts

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';

import { Animals } from '<your path>';
import { BodyParts } from '<your path>';
import { ColorsShapes } from '<your path>';
import { Apparels } from '<your path>';
import { Family } from '<your path>';
import { VegetablesFruits } from '<your path>';

@Injectable()
export class CatagoriesProvider {
data:any;
  constructor(public http: Http) {
    this.data = [
      {component: Animals, catagoryName: 'Animals'},
      {component: BodyParts, catagoryName: 'Body Parts'},
      {component: ColorsShapes, catagoryName: 'Colors & Shapes'},
      {component: Apparels, catagoryName: 'Apparels' },
      {component: Family, catagoryName: 'Family' },
      {component: VegetablesFruits, catagoryName: 'Vegetables & Fruits'}
    ];
  }

  loadAll() {
    return Promise.resolve(this.data);
  }
}

Then in your home.html you want to use the component key to open the page


<ion-content padding>
  <ion-card *ngFor="let catagory of catagoryList">
    <ion-card-header text-center>
      {{catagory.catagoryName}}
    </ion-card-header>
    <ion-card-content text-center>
      <button ion-button small outline (click)="openPage(catagory.component)">Learn</button> <button ion-button small outline>Practice</button>
    </ion-card-content>
  </ion-card>
</ion-content>

And in your home.ts you want to use the passed parameter

...
import { AnimalCategoriesPage } from '../animal-categories/animal-categories';
import { BodyPartsPage } from '../body-parts/body-parts';
import { ColorsShapes } from '<your path>';
import { Apparels } from '<your path>';
import { Family } from '<your path>';
import { VegetablesFruits } from '<your path>';
...

openPage(component) {
    this.navCtrl.push(component);
}

Also make sure to import the pages in your App component and have the pages imported in your home.ts

Like @rapropos said, you can go with lazy loading, if you use a string, which has to be the deeplink representation of the page (e.g. ‘BodyPartsPage’), instead of a page component. For this, you would have to add the
@IonicPage() decorator to the component.

Since I’m not on the computer right now, please state, if any of that worked for you.

1 Like

Thank you very much… That code has worked for me. Can you please which is best to use lazy loading or current working one. If you give brief points on it. I will try to implement best one.

Both options work well and should not have a huge impact in performance.
The general advantages of lazy loading would be
*slightly better performance
*less data traffic for the host
This ist due to the concept, that lazy loaded content should only then be loaded, when directly viewed.

My personal favorite, at least in Ionic, would still be the classic approach with the inclusion of the component, because you get better readability and mantainability because you’re refering to a component and not a string.
The performance should also be no factor in Ionic2.
Also I’d say, it’s good Angular style

Hope, that helped.

Thanks for your quick reply… And i learnt new things today.

IMHO, the primary reason to avoid lazy loading is when you have relatively heavy components that are used in multiple lazily-loaded pages, because you will get duplicate copies of all that component code for each page.

2 Likes