question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Make Material modules compatible with lazy-loaded components

See original GitHub issue

Bug, feature request, or proposal:

Proposal

What is the expected behavior?

Services that are only practically useful as singletons should be available as such. MdIconRegistry is a perfect example. SinceMdIconRegistry.addSvgIconSet() adds icons that should be available app-wide, this service is most useful as a singleton. Instead of simply offering MdIconModule as an export, offer MdIconModule.forRoot as an alternative that can be used to add providers only to the root module in accordance with the Angular docs. So my proposal is to remove services that are meant to be used as a singleton by client modules from the providers arrays of material modules. Change

@NgModule({
  providers:    [ MdIconRegistry]
})
export class MdIconModule{ }

to

@NgModule({
  providers: [] //empty since we want a singleton service
})
export class MdIconModule{
  static forRoot() {
    return {ngModule: MdIconModule, providers: [ MdIconRegistry]};
  }
}

So that in the root AppModule we can import MdIconModule.forRoot(), thus registering its provider just once to all components including lazy-loaded ones.

What is the current behavior?

Because even services that should be singletons are included in the providers array of their respective Material modules, I don’t know how it’s possible to make them singletons. To pick up the example above, when I execute MdIconRegistry.addSvgIconSet() in my AppComponent, the icons are not visible to lazy-loaded modules because they have a different Angular services injector.

What are the steps to reproduce?

Open this plunker and navigate to the LazyLoadedComponent view. You’ll notice that the icon doesn’t show up and the console logs the error below:

Error retrieving icon: Error: Unable to find icon with the name “:play”

What is the use-case or motivation for changing an existing behavior?

The current setup makes services that are only practical as singletons really difficult to use. The only workarounds I’ve found are:

  • Load the whole app at bootstrap (no lazy-loading): this obviously has very negative performance repercussions
  • Register the same icon set in every component: this triggers a new http request for the same file every time the user navigates, not only harming client performance but also taxing the server

Which versions of Angular, Material, OS, browsers are affected?

Angular 2 rc.5 with Material 2 alpha 7-3

Is there anything else we should know?

I’ve been studying this issue for a while now and this post is the culmination of my observations in #1022 and #1016 . The Angular docs recommend a strategy akin to what I propose here:

forRoot and forChild are conventional names for methods that deliver different import values to root and feature modules. Follow the convention when you write similar modules for your application.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:3
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
medeirosrichcommented, Sep 21, 2017

@RoxKilly Does this still require a workaround? @jelbourn mentioned it should be fixed, Could someone please provide a working example if there is a proper way to do this?

1reaction
RoxKillycommented, Aug 19, 2016

A user with the handle ‘James’ on StackOverflow helped me find an acceptable workaround until lazy routes are supported.

Basically, instead of importing MdIconModule, build a custom module (I call it MdIconFixedModule) that declares and exports MdIcon, but that has an empty providers array:

@NgModule({
    imports: [CommonModule, HttpModule],
    declarations: [MdIcon],
    exports: [MdIcon],
    providers: [],//leave empty to avoid multiple instances of MdIconRegistry
})
export class MdIconFixedModule {
    static forRoot() {
        return {
            ngModule: MdIconFixedModule,
            providers: [MdIconRegistry] //will be available only to whoever calls .forRoot()
        };
    }
}

Import MdIconFixedModule.forRoot() into AppModule. This provides both MdIcon and a singleton MdIconRegistry. To use icons in other modules, import MdIconFixedModule. This makes MdIcon available without a separate instance of MdIconRegistry, thus fixing the problem.

See this workaround on plunker

Read more comments on GitHub >

github_iconTop Results From Across the Web

Which way is the best for lazy load angular material modules?
If you want create shared components (and import them into different modules), you should create a single angular-material.module.ts and ...
Read more >
Lazy-loading feature modules - Angular
To lazy load Angular modules, use loadChildren (instead of component ) in your AppRoutingModule routes configuration as follows. AppRoutingModule (excerpt)
Read more >
Lazy Loading in Angular – A Beginner's Guide to NgModules
Lazy loading is the process of loading components, modules, or other assets of a website as they're required. Since Angular creates a SPA ......
Read more >
Lazy load Angular components - Medium
Yes, the current Angular version only supports lazy loading of modules. But Ivy offers us new possibilities. Lazy loading so far — Lazy...
Read more >
Stop Using Shared Material Module - Angular inDepth
I am working on a new project which has many modules, and it has more than 20k Lines of Code, and I was...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found