RC.0: How do you import/export modules into your app?

The Angular Style guide recommends the use of feature modules (see: app structure & modules). Plus, it seems that source maps for ionic2@RC.0 are also only created for modules – the pages folder is missing.

So I’d like to create a ./pages/pages.module.ts that exports all the pages in the default tab project.

This is what I have:

app.modules.ts

// app.modules.ts
import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';


import { MyApp } from './app.component';
// import { AboutPage } from '../pages/about/about';
// import { ContactPage } from '../pages/contact/contact';
// import { HomePage } from '../pages/home/home';
// import { MappiPage } from '../pages/mappi/mappi';
// import { TabsPage } from '../pages/tabs/tabs';
import { PagesModule } from '../pages/pages.module';

@NgModule({
  declarations: [
    MyApp,
    // AboutPage,
    // ContactPage,
    // HomePage,
    // MappiPage,
    // TabsPage
  ],
  imports: [
    IonicModule.forRoot(MyApp),
    PagesModule.forRoot()

  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    // AboutPage,
    // ContactPage,
    // HomePage,
    // MappiPage,
    // TabsPage
  ],
  providers: []
})
export class AppModule {}

./pages/pages.module.ts

// ./pages/pages.module.ts
import { NgModule, ModuleWithProviders } from '@angular/core';

import {AboutPage} from './about/about';
import {ContactPage} from './contact/contact';
import {HomePage} from './home/home';
import {TabsPage} from './tabs/tabs';

@NgModule({
  imports: [],
  declarations: [
    AboutPage,
    ContactPage,
    HomePage,
    MappiPage,
    TabsPage
  ],
  exports: [
    AboutPage,
    ContactPage,
    HomePage,
    MappiPage,
    TabsPage
  ],
  providers: []
})
export class PagesModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: PagesModule,
      providers: [ ]
    };
  }
}

But I am missing the import which gives me access to all the Ionic components. I get these errors in the ChromeDevConsole

polyfills.js:3 Unhandled Promise rejection: Template parse errors:
'ion-title' is not a known element:
1. If 'ion-title' is an Angular component, then verify that it is part of this module.
2. If 'ion-title' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("<ion-header>
  <ion-navbar>
    [ERROR ->]<ion-title>
      About
    </ion-title>
"): AboutPage@2:4
'ion-navbar' is not a known element:
1. If 'ion-navbar' is an Angular component, then verify that it is part of this module.
2. If 'ion-navbar' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("<ion-header>
  [ERROR ->]<ion-navbar>
    <ion-title>
      About
"): AboutPage@1:2
'ion-header' is not a known element:
1. If 'ion-header' is an Angular component, then verify that it is part of this module.
2. If 'ion-header' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("[ERROR ->]<ion-header>
  <ion-navbar>
    <ion-title>
"): AboutPage@0:0
'ion-content' is not a known element:
1. If 'ion-content' is an Angular component, then verify that it is part of this module.
2. If 'ion-content' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("
</ion-header>

...
1 Like

Running into the same problem.

Running into the same problem. +1

same problem here +1

Same problem for me +1

I don’t know much about it but I think you didn’t tell angular to bootstrap the AppModule.

create a main.ts file.

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule }             from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

I think that happens in main.dev.ts. There is also a main.prod.ts that is used when you enable production mode. Both of those files are in the app folder if you want to take a look.

-Dharsan

This is what seems to fix the problem with ion-title etc

import { CommonModule } from '@angular/common';     // contains angular2 components like *ngIf
import { IonicModule } from 'ionic-angular';  // contains ionic2 components like <ion-title>

@NgModule({
imports: [
  CommonModule,                              // for ng2 directives
  IonicModule.forRoot(`root element here`),  // root element for this module 
],
declarations: [
   TabsPage,
   ...
],
exports:[
   TabsPage,
   ...
],
providers[]
})
export class PagesModule {}

But I’m still not able to use TabsPage from this module in the AppModule

app.module.ts

// ...
import { PagesModule } from '../pages/pages.module';

@NgModule({
  declarations: [
    MyApp,
    PagesModule,
  ],
  imports: [
    IonicModule.forRoot(MyApp),
    PagesModule.forRoot(),
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
  ],
  providers: []
})
export class AppModule {}

That issue is more accurately addressed in this post: How do you import a Component that is exported by a Feature Module?

Hey I got mine to work with just the home page. @mixofia, I would try and remove PagesModule from declarations (from what I’ve seen just components, directives, and pipes go there but I could be wrong about that). Then in the imports just import PagesModule without the forRoot().

I haven’t gotten the tabs page to work, instead I used the home page. Here’s what I have for the HomeModule:

import { NgModule }           from '@angular/core';
import { CommonModule }       from '@angular/common';
import { FormsModule }        from '@angular/forms';
import { HomePage }           from './home';
import { IonicModule} from 'ionic-angular';

@NgModule({
  imports:      [ CommonModule, FormsModule, IonicModule.forRoot(HomePage) ],
  declarations: [ HomePage ],
  exports:      [ HomePage ]
})
export class HomeModule { }

And app.module.ts:
import { HomeModule } from ‘…/pages/home/home.module’;

@NgModule({
  declarations: [
    MyApp
  ],
  imports: [
    HomeModule,
    IonicModule.forRoot(MyApp),
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
  ],
  providers: []
})
export class AppModule {}

Hi all,

Here is the default example with a pages module.

PagesModule:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { AboutPage } from './about/about';
import { ContactPage } from './contact/contact';
import { HomePage } from './home/home';
import { TabsPage } from './tabs/tabs';
import { IonicModule } from 'ionic-angular';

@NgModule({
    imports: [
        CommonModule,
        FormsModule,
        IonicModule.forRoot(AboutPage),
        IonicModule.forRoot(ContactPage),
        IonicModule.forRoot(HomePage),
        IonicModule.forRoot(TabsPage)
    ],
    declarations: [
        AboutPage,
        ContactPage,
        HomePage,
        TabsPage
    ],
    exports: [
        AboutPage,
        ContactPage,
        HomePage,
        TabsPage
    ]
})
export class PagesModule { }

AppModule:

import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { PagesModule } from '../pages/pages.module';

@NgModule({
  declarations: [
    MyApp
  ],
  imports: [
    PagesModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp
  ],
  providers: []
})
export class AppModule {}

Hope that helps!
-Dharsan

3 Likes

Glad you were able to get this working. Adding it to the list of things we can look into for documentation purposes…

1 Like

This is awesome. It should be added to the documentation, especially if people are going to follow the angular2 style guide. I’m going to have to read up on how/when to use IonicModule.forRoot()

Unfortunately, it doesn’t completely solve my source maps issue, only pages.module.js seems to appear…

1 Like

Following are my changes and it works for me.

Add home.module.ts to home folder with contents:

import {NgModule} from '@angular/core';
import {HomePage} from "./home";
import {IonicModule} from 'ionic-angular'

@NgModule({
  imports:[IonicModule],  //no forRoot here
  declarations:[HomePage],
  exports:[HomePage],
  entryComponents:[HomePage]  //<-- add all your module components to here
})
export class HomeModule{

}

Add contact.module.ts to contact folder with contents:

import {NgModule} from '@angular/core';
import {ContactPage} from "./contact";
import {IonicModule} from 'ionic-angular'

@NgModule({
  imports:[IonicModule],
  declarations:[ContactPage],
  exports:[ContactPage],
  entryComponents:[ContactPage]
})
export class ContactModule{

}

Add about.module.ts to about folder with contents:

import {NgModule} from '@angular/core';
import {AboutPage} from "./about";
import {IonicModule} from 'ionic-angular'

@NgModule({
  imports:[IonicModule],
  declarations:[AboutPage],
  exports:[AboutPage],
  entryComponents:[AboutPage]
})
export class AboutModule{

}

Add tabs.module.ts to folder tabs with contents:

import {NgModule} from '@angular/core';
import {IonicModule} from 'ionic-angular'
import {TabsPage} from "./tabs";
import {HomeModule} from '../home/home.module';
import {AboutModule} from '../about/about.module';
import {ContactModule} from '../contact/contact.module';

@NgModule({
  imports:[IonicModule, HomeModule, AboutModule, ContactModule],  //<--no forRoot here and add HomeModule,AboutModule,ContactModule
  declarations:[TabsPage],
  exports:[TabsPage],
  entryComponents:[TabsPage]  //<--add all your module components to here
})
export class TabsModule{

}

Update app.nodule.ts in folder app:

import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
//import { AboutPage } from '../pages/about/about';
//import { ContactPage } from '../pages/contact/contact';
//import { HomePage } from '../pages/home/home';
//import {HomeModule} from '../pages/home/home.module'; //<--no need child level module
import { TabsModule } from '../pages/tabs/tabs.module'; //<--import top level module only

@NgModule({
  declarations: [
    MyApp,
    //AboutPage,
    //ContactPage,
    //HomePage,
    //TabsPage
  ],
  imports: [
    TabsModule, //<-- top level module only
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    //AboutPage,
    //ContactPage,
    //HomePage,
    //TabsPage
  ],
  providers: []
})
export class AppModule {}

4 Likes

@yubin_zhu Whats the reason\purpose that you do it like this?

This is called abstraction. You need to make your certain pages not be accessible from another modules.

@yubin_zhu that is a much clearer solution!

Hi @yubin_zhu, thanks for the tips.

Could you share the contents of your TabPage component here?

Does it import the component pages like so:

import { Component } from '@angular/core';
import { HomePage } from './home/home-page.component';
import { AboutPage } from './about/about-page.component';
import { Contact } from './contact/contact-page.component';

@Component({
  templateUrl: 'tabs-page.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 = Contact;

  constructor() {}
}

Is there any way of getting around the direct imports of the HomePage, AboutPage, ContactPage components? I’m basically looking for a way to avoid having to dive down into those feature modules to get actual component references, but not sure what my options are here. Is it possible to reference them by selector instead?

Just to clarify, I’m trying to do something like this:

<ion-tabs>
  <home-page></home-page>
  <about-page></about-page>
  <contact-page></contact-page>
</ion-tabs>

To take advantage of the exported HomePage, AboutPage, ContactPage that was declared/exported from each of the individual feature modules. I’d like to not have to import that type and have a direct reference to it, but instead let the component markup drive the tab component.

Hi, @Giannico, my Tab.ts is like what you have here. But you can do something like this:
You can put and index.ts under home folder (each module folder and export all components in that folder):

export * from './home';

and in Tabs.ts :

import HomePage from '../home';

For this ionic tabs component, I didn’t use selector directly like what you show below(I don’t think it will work). But inside of home.html I’m using selector to include other components. It looks like this:

<ion-content padding #content class="main-landing">
  <h3 menuToggle class="menu-toggle">
    <ion-icon name="menu"></ion-icon>
  </h3>
  <horizontal-scroll-container></horizontal-scroll-container>
</ion-content>

Thanks @yubin_zhu, that’s kind of what I was expecting. In a basic Angular2 app I usually try to create a local router for each module, so as to not have to export any of the pieces/components of the module (I just export the module itself).

Sounds like I may need to adjust this strategy slightly with Ionic and export both the module and the “Page”. Thanks again for the example!