0

I created and successfully lazily loaded LazyAComponent component.

I didn't have to declare LazyAComponent in the app.module. PERFECT!

However, if I place a component, HelloComponent, on LazyAComponent; I get the error 'hello' is not a known element

I was able to workaround this error by declaring LazyAComponent in the app.module.

However, if I have to declare the component in order to get this work then lazy loading the component has no value whatsoever!?

What am I missing???

EDIT 1: For clarity, this is a part of a much larger project where I am trying to lazy load a component based on the route parameter. Stackblitz does not allow me to illustrate this, however, my real code is loading the component like so:

const template = paramMap.get('template');

const esModule = await import(`/src/app/features/admin/components/article-editor/article-templates/${template}-template/${template}-template.component`);

const componentClassName = 'Eai' + tempalte + 'TemplateComponent';

return esModule[componentClassName];

This is actually working, I had to include the lazy-a folder in the tsconfig, however, as illustrated, it falls apart once I place a custom child component in the template.

EDIT 2: I guess I don't understand the value of lazy and dynamically loading components if you have to manually bootstrap all of it??? Thanks to Nicolas below, I got past my original error, however, after registering my component from the lazy component, the child component could not recognize the "async" pipe.

I'm sure it has uses, but to me w/o this ability, this feature feels very, very useless. I could just be architecting the project wrong?

EDIT 3: OK, thanks everyone. I guess I expected way too much "magic" from Angular. As I understand what I would want/need to do is lazy load each article template and have them share a common set of sub-components (article-blocks) among them.

That being said, we might have up to 50 or more article templates. That 50+ modules. That might be acceptable, however, that also means 50+ route definitions. Is there a way to dynamically lazy load modules based on a route parameter?

Something like:

  {
    path: 'article/:template',
    loadChildren: () => import('./features/article/${template}/${template}.module').then((m) => m[template]),
  }

https://stackblitz.com/edit/angular-ivy-pxar92?devtoolsheight=33&file=src/app/app.component.ts

3
  • You have <hello> in your lazy-a template. It's best to remove the gunk that stackblitz starts you off with. Commented Feb 11, 2021 at 21:50
  • @Phix correct, I actually want the hello component in my lazy-a template. That is actually what I'm tying to accomplish :) Commented Feb 11, 2021 at 21:56
  • Gotcha. Misunderstood the question. Commented Feb 11, 2021 at 22:38

2 Answers 2

1

In order to do so you need to load your HelloComponent from within the LazyAComponent

export class LazyAComponent implements OnInit {
  name = "yup";

  constructor(
    private viewContainerRef: ViewContainerRef,
    private cfr: ComponentFactoryResolver
  ) {}

  ngOnInit() {
    const componentFactorya = this.cfr.resolveComponentFactory(HelloComponent);
    let component = this.viewContainerRef.createComponent(componentFactorya);
    component.instance.name = this.name;
  }
}
<!-- <hello name="{{ name }}"></hello> -->
<p>
    lazy-a works!
</p>

here is the adjusted blitz https://stackblitz.com/edit/angular-ivy-2fgeys

You can find more details in this article: https://johnpapa.net/angular-9-lazy-loading-components/#6whatiflazyloadedcomponentshavechildren

Edit 1: for more flexibility you can use this instead which allow you to specify exactly where the child component should be added https://stackblitz.com/edit/angular-ivy-yqccuu

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much, that does indeed solve the problem at hand. That's kind of a bummer though! We may have 10, 20, who knows how many child components. The goal is offload the creation of these templates to entry level team of developers and keep the process as simple as possible. I don't want them to have to manually register the child components :(
I totally understand your issue, I have been there myself. Unfortunately, to the best of my knowledge, this is currently the only way to do, hopefully angular team can introduce a simpler way in the future.
1

In your example you use a dynamic component. In a sense you don't declare the component but you create it on the fly programmatically.

I don't see the need to lazy load that component. Just use it when you want to use it in your code and it will be available only then.

Keep in mind that in Angular we normally have

  • Dynamic Components (like the one you have)
  • Lazy loaded modules

Lazy means don't load the code in the client (browser) until it is needed.

So if you want what you have written to work then you must pack lazy component inside a module which will be lazy loaded. Then it can have a static reference to a hello component as it has as this module will have declared on it's imports the HelloComponent

1 Comment

thanks! I edited my original questions, you are correct, however, I am using lazy loading because in real life I am lazy loading from a list of over 50 components.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.