Ionic-framework: BUG in LazyLoading - Can't use custom components

Created on 8 May 2017  路  27Comments  路  Source: ionic-team/ionic-framework

Ionic version: (check one with "x")
[x] 3.x

I'm submitting a ... (check one with "x")
[x] bug report

What I Did:

  1. I've started a new app using ionic start app
  2. I've removed all demo pages (including all references in the app.module.ts of course!)
  3. I've created some pages. Using for example ionic g page welcome
  4. I've set the main rootPage in app.component.ts to rootPage:any = 'Welcome';
  5. I've started the app using ionic serve. Everything is fine. The welcome page shows up as expected.

=== UNTIL HERE EVERYTHING WORKS AS EXPECTED ===

  1. I've created a custom component using ionic g component do-toolbar
  2. I've imported the component's module in the app.module.ts and added the reference to the import section.
  3. I've added a <do-toolbar></do-toolbar> tag to the welcome page's template.
  4. The app is now broken and this error is shown:
Error: Template parse errors: 'do-toolbar' is not a known element

Current behavior:
App crashes with error message as described above.

IMPORTANT: The custom components can be used perfectly if the pages, which rely on custom components, aren't lazy loaded.

Expected behavior:
Well, the component should be displayed.

Steps to reproduce:
See What I Did above.

I've created a very simple app, demonstrating this bug. Please keep in mind, that all pages are loaded by the newly added lazy loading feature.

https://github.com/tobiasmuecksch/ionic3-custom-component-bug

Ionic CLI Version
$ ionic -v
=> 2.2.3

Most helpful comment

I don't know if what you are trying to do is supposed to work or not, but what I know does work:

  • define a DoToolbarModule module that declares and exports DoToolbarComponent
  • import DoToolbarModule in the modules of all lazily loaded pages that incorporate <do-toolbar> elements

All 27 comments

Thanks for opening an issue with us, we will look into this.

I don't know if what you are trying to do is supposed to work or not, but what I know does work:

  • define a DoToolbarModule module that declares and exports DoToolbarComponent
  • import DoToolbarModule in the modules of all lazily loaded pages that incorporate <do-toolbar> elements

@rapropos thanks. I will try that. Is there any reliable documentation on how to properly use the lazy loading?

I only found the following link, and in this article they import the pipe and component modules in the app.module.ts (See sections 5&6)

https://ionicacademy.com/ionic-3-lazy-loading/

Importing it to the page module directly, just like @rapropos suggested, works. Thank you very much for that!

But is that what the Ionic guys intended us to do?
Will there be an official article on 'how to properly implement the lazy loading' in the ionic docs or somewhere else?

Could someone of the Ionic Team please say just a few words ? If this behavior is intended I will close this issue of course.

@tobiasmuecksch take a look at this doc Ionic 3 Lazy Loading

@AbuHani Thank you for that link.

But I've got a problem with this:
In this document, you can see that they create one components.module.ts in the components folder that imports all other components. In fact - I like that. But with the the latest version of the ionic cli, ionic g component my-component creates a seperate module for each component. That's not consistent with this document.

So that might be an indicator that either:

  1. The generator behaves wrong
    -or-
  2. This document is outdated

you can see that they create one components.module.ts in the components folder that imports all other components. In fact - I like that

One thing to be wary of is that this will exacerbate the code duplication problem, in that now you will have multiple copies of the code for all your components, one for each page that includes any of them.

@rapropos i don't get your point. Where's the code duplication, when there's one file to include them all ?

@tobiasmuecksch
Using one module for all components means everytime you use only one component you will still load the code of the other components. Creating one module for each component solves this as you only import the component you want to use.

Both ways have their pros and cons

@digaus Thank you for the clarification.

But what about components, that are potentially used on every page - like a custom header toolbar ? I don't think it's very convenient to import such components in each and every page module.

And further more - would the lazy loading feature detect multiple used components and only load them once, or will it load the components freshly every time? I can imagine that such behavior could cause performance issues.

@tobiasmuecksch see app-scripts #867 for more information. When lazy page loading is enabled, you get a separate ###.main.js chunk for each lazy page, in addition to the main.js that holds all the core framework stuff. The code for all your custom components gets duplicated in every ###.main.js that imports that component module, and when it is all zipped up into an APK, you end up with multiple copies of component code. My app binary blew up by about 35% because of this, so I decided to opt out of lazy loading on that app.

@rapropos Thank you for that explanation. I hope they will come up with a better solution. In general I never liked to import all the pages (and so on) in the app.module.ts. As the app grows, this file get's very unhandy and unreadable.

You could still combine severel components into one module.

But in that case, when I'm adding a module to the app.module.ts I can't use the lazy loading feature anymore, because it wouldn't be available - as described in this issue.

@jgw96 Why have you tagged this issue as v2. This issue is about a v3 only feature.

Hello! After further review, this seems like more of a support question. Because of this, I will urge that you ask this question on our forum or on our slack channel. Thanks for using Ionic!

I am also facing this issue. :|
I have not found a solution yet.

I am using lazy loaded pages.
I created a component with ionic g component Test.
If I add <test></test> into the page.html I get an error telling me that angular does not recognise the selector even though it was globally declared in app.module.ts.

Adding the declaration to the loaded pages creates an error that the declaration was made multiple times and I should add it to a higher module. Which does not make sense since it is already in app.module.ts which is the highest possible one.

Ideas of how to solve this? (apart from disabling lazy load)

@Eraldo I found the solution here:
https://stackoverflow.com/questions/43507800/custom-component-in-ionic-v3/43514723

The idea is not to add the component in the ngModule and just import it in the .module.ts of the page you want to show the component.

Hope this helps.

@Eraldo Thanks that worked for me. I had spent far too long looking for a solution. The link does not work however. Use https://stackoverflow.com/questions/43507800/custom-component-in-ionic-v3

not working, the idea is to keep it lazy, not importing it in the app.module.ts.

What @walfridosp suggested worked for me - you import into the relevant page's module.ts file, rather than the page's .ts file or the app.module.ts file.

@lepabloski unfortunately there's no way to make lazy load component, directive, pipe. any way let us know if you manage it.

Lazy load concept is pretty awesome but custom components are hard to integrate with pages. Needs a better and stable solution.

Here in Feb 2018 and using custom components or pipes on lazy loaded pages simply just does not work

ngAfterViewInit() function doesn't work when rendering the custom component in page which have lazy loading.

After successfully using the CUSTOM_ELEMENTS_SCHEMA declarations in my modules and which forces you to name your selectors with a "-" dash, so I would have to use something like:

<MyPlayer-comp></MyPlayer-comp>

I was upset with this total non-sense from these frameworks camel-case freaks even though it worked and ngc no longer complained about "...is not a known element...".

I personally prefer to name everything the same (the class, the selector, the file, etc...)

I reverted to the following which is working with lazy-loading while I build for the web. (ionic cordova build browser --prod --release)

Your custom component module declarations:

import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
//
import { MyPlayerComp } from './MyPlayerComp ';
//
@NgModule({
    declarations: [MyPlayerComp ],
    imports: [IonicPageModule.forChild(MyPlayerComp )],
    exports: [MyPlayerComp ],
})
export class MyPlayerCompModule { }

In the modules where you want to use your custom component use the following:

import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
//
import { PlyrView } from './PlyrView';
//
import { MyPlayerCompModule } from './MyPlayerComp.module' // 20180720
//
@NgModule({
    declarations: [PlyrView],
    imports: [
        IonicPageModule.forChild(PlyrView),
        MyPlayerCompModule,                      // <<<<<
    ],                
    exports: [PlyrView],
})
export class PlyrViewModule { }

I hope this helps someone

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

BilelKrichen picture BilelKrichen  路  3Comments

GeorgeAnanthSoosai picture GeorgeAnanthSoosai  路  3Comments

danbucholtz picture danbucholtz  路  3Comments

vswarte picture vswarte  路  3Comments

MrBokeh picture MrBokeh  路  3Comments