Ionic 2 lazy loading components - ionic2

My app is really big and has like 30 components and pages, I load all of them in my app.module.ts and sometimes the application turn slow. I wonder if it has anything to do it.
My question: What's the correct way to lazy load components and use angular 2 features (more modules) with Ionic 2?

Since Ionic 3, you can lazy load components.
Simply, create a new module for each component/page.
Here's an example of how a module of the HomePage should look like:
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
#NgModule({
declarations: [MyApp, HomePage],
imports: [ ... ],
bootstrap: [IonicApp],
entryComponents: [MyApp, HomePage],
providers: [ ... ]
})
export class AppModule {}
After creating the module, attach #IonicPage() to the component:
import { Component } from '#angular/core';
import { IonicPage } from 'ionic-angular';
#IonicPage()
#Component(... )
export class HomePage { ... }
Now you can use your page/component as a string without using the import statement:
rootPage:any = 'HomePage';
for more descriptibe answer, check out this Ionic Lazy Loading blog post.

Related

Ionic3 lazy loaded modules entry components

In my Ionic app I have a page called "MyCustomer". MyCustomer page has the following IonicPage Config:
#IonicPage({
name: 'MyCustomer',
})
From MyCustomer page I will be opening a component called "CustomerEdit" in modal. So I have defined the CustomerEdit component in MyCustomer Page module file in both declarations and entry components and below is the #NgModule code for Page
import { NgModule } from '#angular/core';
import { IonicPageModule } from 'ionic-angular';
import { CommonModule } from '#angular/common';
import { MyCustomerPage } from './my-customer.page';
import { CustomerEdit } from '../../components/CustomerEdit/CustomerEdit';
#NgModule({
declarations: [
MyCustomerPage,CustomerEdit
],
imports: [
CommonModule,IonicPageModule,
IonicPageModule.forChild(MyCustomerPage),
],
entryComponents:[CustomerEdit]
})
export class MyCustomerPageModule {}
When I try to open the CustomerEdit component in modal like this
Open(){
let modal=this.modalCtrl.create(CustomerEdit);
modal.present();
}
I get the following error.
No component factory found for CustomerEdit. Did you add it to #NgModule.entryComponents?
What am I doing wrong here?

Working Example of an Unit Test of a Ionic Page with lazy load

For some time I am trying to rewrite my 'broken' unit tests since lazy loading with IonicPageModule, without any luck.
Anyone who has some pointers or working examples is greatly appreciated.
Should no working example exist (which I doubt), I will help create one with the feedback gathered on this page.
Any help is welcome.
Thanks to the help of RomainFallet I've found (and recreated) a working ionic 3 Unit Test with lazy loading on his github (see 2.7), which I also share here for ease.
/* Import Ionic & Angular core elements */
import { async, TestBed } from '#angular/core/testing';
import { IonicModule } from 'ionic-angular';
/* Import modules */
import { HomePageModule } from './home.module';
/* Import components */
import { AppComponent } from '../../app/app.component';
/* Import pages */
import { HomePage } from './home';
describe('HomePage', () => {
let fixture;
let component;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [],
imports: [
IonicModule.forRoot(AppComponent),
HomePageModule
],
providers: [
]
})
}));
beforeEach(() => {
fixture = TestBed.createComponent(HomePage);
component = fixture.componentInstance;
});
it ('should create a valid instance of HomePage', () => {
expect(component instanceof HomePage).toBe(true);
});
});
Hope it also helps others finding their way.

In Ionic 2, version 3.0.1 how do I create a custom component that uses Ionic components?

In Ionic 2, how do I create a custom directive that uses Ionic components?
This answer doesn't work anymore.
import {IONIC_DIRECTIVES} from 'ionic-angular'
this also doesn't work. How can i create a custom component that uses Ionic components in Ionic 2, version 3.0.1?
If you stuck with this problem after using lazy loading you should do that like that:
Add IonicModule to 'imports' parameter of CustomComponentModule
Use ionic components in custom components' templates
Add CustomComponentModule to 'imports' parameter of your AnotherComponentModule where you want use that component (CustomComponentModule).
deletable.module.ts
import { NgModule } from '#angular/core';
import { DeletableItem } from './deletable';
import { IonicModule } from 'ionic-angular';
#NgModule({
declarations: [
DeletableItem
],
imports: [
IonicModule
],
exports: [
DeletableItem
]
})
export class DeletableModule {}
bill.html
<ion-content padding>
<ion-list>
<ion-item *ngFor="let bill of bills" (click)="openEdit(bill)">
<ion-label text-left>{{bill.name}}</ion-label>
<ion-label text-right>{{bill.amount}}</ion-label>
<deletableItem></deletableItem>
</ion-item>
</ion-list>
</ion-content>
bill.module.ts
import { NgModule } from '#angular/core';
import { IonicPageModule } from 'ionic-angular';
import { BillPage } from './bill';
import { DeletableModule } from './../../components/deletable/deletable.module'
#NgModule({
declarations: [
BillPage
],
imports: [
IonicPageModule.forChild(BillPage),
DeletableModule
],
exports: [
BillPage
]
})
export class BillModule {}
That's work for me.

IonicPage is not working

I am using instructions at IonicPage Documentation
But I am getting the following error:
Error: /app/src/pages/subscribe-channel/subscribe-channel.ts has a
#IonicPage decorator,
but it does not have a corresponding "NgModule" at /app/src/pages/subscribe-channel/subscribe-channel.module.ts
To be specific, I made the following changes prescribed in the docs:
added IonicPageModule.forChild(SubscribeChannelPage)
added #IonicPage() on the component i.e. SubscribeChannelPage
I am unable to share code sample, since it is part of the larger application.
A similar error is reported here:
Page has a #IonicPage decorator, but it does not have a corresponding "NgModule"
IonicPage is commented out in the answer suggested there to get rid of this error. However, I am trying to make use of IonicPage and would like to know how to make it work.
Here is subscribe-channel.ts
import { Component, OnInit } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { IonicPage } from 'ionic-angular';
#IonicPage()
#Component({
selector: 'page-subscribe-channel',
templateUrl: 'subscribe-channel.html'
})
export class SubscribeChannelPage implements OnInit {
constructor() {
}
ngOnInit() {
}
}
and here is app.modules.ts
import { NgModule, ErrorHandler, APP_INITIALIZER } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { HttpModule } from '#angular/http';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { IonicPageModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { SubscribeChannelPage } from '../pages/subscribe-channel/subscribe-channel';
#NgModule({
declarations: [
MyApp,
SubscribeChannelPage
],
imports: [
BrowserModule,
HttpModule,
IonicModule.forRoot(MyApp),
IonicPageModule.forChild(SubscribeChannelPage)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
SubscribeChannelPage
],
providers: [
StatusBar,
SplashScreen,
{ provide: ErrorHandler, useClass: IonicErrorHandler }
]
})
export class AppModule { }
#gerdi, suggestions in the answer helped in avoiding the compilation errors. However, the deep-link still does not work, it takes to default page.
FYI, the deep-link was working earlier with following code in app.module.ts . However, I am trying the IonicPage assuming it is a better option for future.
IonicModule.forRoot(MyApp, {}, {
links: [
{ component: SubscribeChannelPage, name: 'subscribe', segment: 'subscribe/:channelId' },
]
}),
In order to use #IonicPage(), the "component page" that you add the decorator to needs to have a connected module.
The error you are getting is basically saying.
You have added the #IonicPage() decorator but there is no associated module for this component. You need to include a subscribe-channel.module.ts file that declares this component in its own module scope.
So you need to add a subscribe-channel.module.ts which is the declaration of a module.
To better understand this you can go into your terminal and generate a new template and see the files that it adds
>_ ionic generate page foobar
Under the foobar folder, you will see 4 files one of them is foobar.module.ts which is the module declaration.
FYI: You need to change
import { IonicModule } from 'ionic-angular';
to
import { IonicPageModule } from 'ionic-angular';
in the generated template. There still seems to be a few issues around this new shiny stuff
However, the deep-link still does not work, it takes to default page.
FYI, the deep-link was working earlier with following code in app.module.ts . However, I am trying the IonicPage assuming it is a better option for future.
For deeplinking you have to now set it in IonicPage() decorator of your required ionic page.
Remove
links: [
{ component: SubscribeChannelPage, name: 'subscribe', segment: 'subscribe/:channelId' },
]
as this was before IonicPage was introduced in ionic 3.x
Try:
#IonicPage({
name: 'SubscribeChannelPage',
segment: 'subscribe/:channelId'
})
in subscribe-channel.ts.
Example Url will be:
http://localhost:8101/#/subscribe/:channelId
The file name of the module is the same as the component:
- login.ts
- login.module.ts
The module needs to be named login in order to correspond.

Failed: No provider for Config! (Icon -> Config) in Ionic2 unit tests with karma and jasmin

I'm writing unit tests for an ionic2 app but I get following error when the template contains some ionic elements
e.g.
<ion-icon > </ion-icon>
Failed: No provider for Config! (Icon -> Config)
Any idea?
I don't see how the previous solution works, because Config needs App, which needs Platform, which needs Keyboard which needs... maybe it is because you do not configure testing module asynchronously, which you should ;) simply try this:
import { IonicModule } from 'ionic-angular';
import { YourTestedComponent } from './pathto.component.ts'
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ IonicModule.forRoot(this) ], // this loads ionic deps
declarations: [ YourTestedComponent ],
});
}));
This should fix it
Best of luck
you're not allowed to use template in #app, try to use templateUrl: 'build/app.html' and create a app.html with your tags in it.
I run into the same problem. This worked for me:
import { async, ComponentFixture, TestBed } from "#angular/core/testing";
import { Config, IonicModule } from "ionic-angular";
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
],
imports: [
IonicModule,
],
providers: [
Config,
],
});
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
});