Ionic3 lazy loaded modules entry components - ionic2

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?

Related

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.

Ionic 2 lazy loading components

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.

Unexpected value 'SohoComponentsModule' imported by the module 'DynamicTestModule'

I am writing an angular 2 application and am using our UI team's library. The development of the application is going great, I can use all of their components easily by using an import statement like so. This is my app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { SohoComponentsModule } from '#infor/sohoxi-angular'; // This is the one in question.
import { AppComponent } from './app.component';
import { licenseGeneratorComponent } from './licenseGenerator.component';
import { emergencyLicenseComponent } from './tabs/emergency/emergencyLicense.component';
import { partnerLicenseComponent } from './tabs/partner/partnerLicense.component';
import { standardLicenseComponent } from './tabs/standard/standardLicense.component';
#NgModule({
declarations: [
AppComponent,
licenseGeneratorComponent,
emergencyLicenseComponent,
partnerLicenseComponent,
standardLicenseComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
SohoComponentsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
and here is one of my templates used within this app, the soho stuff is from this library:
<div class="row">
<div class="twelve columns">
<h1>License Generator</h1>
<div soho-tabs>
<ul soho-tab-list>
<li soho-tab><a soho-tab-title tabId='tabs-normal-emergency'>Emergency Licenses</a></li>
<li soho-tab><a soho-tab-title tabId='tabs-normal-partner'>Partner Licenses</a></li>
<li soho-tab><a soho-tab-title tabId='tabs-normal-standard'>Standard Licenses</a></li>
</ul>
<div soho-tab-panel tabId='tabs-normal-emergency'>
<emergency-license></emergency-license>
</div>
<div soho-tab-panel tabId='tabs-normal-partner'>
<partner-license></partner-license>
</div>
<div soho-tab-panel tabId='tabs-normal-standard'>
<standard-license></standard-license>
</div>
</div>
</div>
</div>
The application has been working just fine, no issues. But when there is an issue with my unit tests now. I had them working before with the first few unit tests but left it alone for a week or so and added more content and now the tests don't run properly.
When I run my tests I get the error
Unexpected value 'SohoComponentsModule' imported by the module 'DynamicTestModule'
My app.component.spec looks like this:
import { TestBed, async } from '#angular/core/testing';
import { FormsModule } from '#angular/forms';
import { AppComponent } from './app.component';
import { licenseGeneratorComponent } from './licenseGenerator.component';
import { emergencyLicenseComponent } from './tabs/emergency/emergencyLicense.component';
import { partnerLicenseComponent } from './tabs/partner/partnerLicense.component';
import { standardLicenseComponent } from './tabs/standard/standardLicense.component';
import { SohoComponentsModule } from '#infor/sohoxi-angular';
describe('AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
licenseGeneratorComponent,
emergencyLicenseComponent,
partnerLicenseComponent,
standardLicenseComponent,
],
imports: [
FormsModule,
SohoComponentsModule
],
});
});
it('should create the app', async(() => {
let fixture = TestBed.createComponent(AppComponent);
let app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'app works!'`, async(() => {
let fixture = TestBed.createComponent(AppComponent);
let app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app works!');
}));
});
I am going in circles now though because if I remove the import statement in the test it throws these errors:
Can't bind to 'closeOnSelect' since it isn't a known property of 'select'. ("label required">Versions</label>
Please Help!
Keep in mind the application works just fine still, just the unit tests that are giving me issues. I've spent all day looking around for fixes but can't figure this out.
Please let me know if I need to post more of my files.
Thanks,
Chris
For some reason it was the angular library that was causing this issue.
I updated the version and the issue was fixed.

Ionic 2 rc0 whitescreen (No provider for ConnectionBackend!)

I started a new ionic 2 rc0 app by copying the files of my old beta11 project. I did the necessary steps as described under
Copying your Project to a New Project : ionic 2 rc0 changelog
Now finally after getting no more compiler errors when I run
ionic run android -c
I'm just getting a whitescreen on my android phone.
Chrome debug is logging me
Uncaught Error: No provider for t!
When I'm running
ionic serve -c
the firefox logs me
Unhandled Promise rejection: No provider for ConnectionBackend! ;
Zone: ; Task: Promise.then ; Value: Object { ...
app.module.ts looks like:
import { NgModule } from '#angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { Storage } from '#ionic/storage'; // special thing
import { Http } from '#angular/http';#
// other imports ....
#NgModule({
declarations: [
MyApp,
// PAGES
// MODALS
// CUSTOM COMPONENTS
// DIRECTIVES
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
// PAGES
// MODALS
],
providers: [
Storage,
Http,
// SERVICES/PROVIDERS
]
})
export class AppModule {}
I'm guessing there is something wrong with a provider somewhere, but I just can't find a solution ...
System : ubuntu 16.04 / node v6.7.0 / npm v3.10.3
EDIT :
I started a new sidemenu project with
ionic start debugProject sidemenu --v2
I did this to to debug the providers by sequentially adding the providers of my original Project. It appears that, when I inject the first provider called "Config" in the constructor of app.components.ts
import { Component } from '#angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from 'ionic-native';
import { TabsPage } from '../pages/tabs/tabs';
// PROVIDERS -> providers
import { Config } from '../providers/config/config';
#Component({
template: `<ion-nav [root]="rootPage"></ion-nav>`
})
export class MyApp {
rootPage = TabsPage;
constructor(
platform : Platform,
config : Config <-------------(HERE !!! )
) { .....
I get the the Error message like before:
Unhandled Promise rejection: No provider for ConnectionBackend! ;
Zone: ; Task: Promise.then ; Value: Object { ...
config.ts
import { Injectable } from '#angular/core';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
// providers
import { Http } from '#angular/http';
//import { DB } from '../db/db';
#Injectable()
export class Config {
public data : any;
constructor(
public http : Http,
//public db : DB
){
this.data = {};
}
loadDefault() {
this.data = {
..........................
// DATA OBJECT DEFINITIONS
...........................
};
return Promise.resolve("default settings applied");
}
loadSettingsFromDB(){
return Promise.resolve("no local settings from db for now");
}
// TODO: send settings to server
saveSettingsToDB(settings){
return Promise.resolve("cant save settings for now");
}
handleError(err) : void {
// error stacktrace gets returned on development mode
try{
err = err.json();
}catch(e){}
var msg = err.message || "LOADING ERROR";
if(err.error){
msg += err.error;
//Toast.showLongBottom(msg).subscribe();
}else{
//Toast.showShortBottom(msg).subscribe();
}
console.log("ERROR in config.ts");
console.log(msg);
console.log(err);
}
}
any ideas ? if not, any experience about opening a new issue on github ?
I found the solution. It seems like I can't/shouldn't use the Http module in the providers array in app.modules.ts (In beta11 this was not a problem). My Config module relied on Http, so after constructing Config the application Error (No provider for ConnectionBackend) fired ...