Angular 2 Material: same icon from same file displ

2019-09-12 05:15发布

问题:

I'm using Angular 2 rc 5 with ng2-Material alpha 7-2.

The basic problem is that using <md-icon svgIcon='icon'> to show the same icon from the same svg file will work in one component but not the other even though MdIconModule and MdIconRegistry are provided to the root AppModule

To replicate the problem

  • Open this plunker
  • Notice that MdIconModule and MdIconRegistry are imported as part of MaterialModule.forRoot() into the main AppModule
  • Open the AppComponent and notice the call to addSvgIconSet() to register icons
  • In the template, <md-icon svgIcon='ic_account_box_24px'> is used to display the icon. In the view the icon is shown successfully above the nav bar.
  • Open app/crisis-center/crisis.list.component and open the Crisis Center in the view.
  • Note in the template, the same <md-icon> is present. However, no icon is displayed above the crisis list in the view. The DOM inspector from browser dev tools shows that the angular parser didn't even recognize it as an angular component (in the dom, it's left exactly as in the code)

Because I imported the icon module and service into the root module I expected the service to be a singleton available to the whole app. Since I use that service to register the icons with iconRegistry.addSvgIconSet() in my bootstrapped AppComponent, I expected the icons to be accessible throughout the app.

PS: this may be related to what I reported yesterday, although in that case the app crashes; in this case the icon is just not shown.

回答1:

import { NgModule, ModuleWithProviders  }       from '@angular/core';
import { MdButtonModule } from '@angular2-material/button';
import { MdCardModule } from '@angular2-material/card';
import { MdCheckboxModule } from '@angular2-material/checkbox';
import { MdCoreModule } from '@angular2-material/core';
import { MdInputModule } from '@angular2-material/input';
import { MdProgressCircleModule } from '@angular2-material/progress-circle';
import { MdToolbarModule } from '@angular2-material/toolbar';
import { MdMenuModule } from '@angular2-material/menu';
import { MdIconModule} from '@angular2-material/icon';

@NgModule({     
    exports:      [
      MdButtonModule,
      MdCardModule,
      MdCheckboxModule,
      MdCoreModule,
      MdInputModule,
      MdProgressCircleModule,
      MdToolbarModule,
      MdMenuModule,
      MdIconModule
    ]
})
export class MaterialModule {

  static forRoot(): ModuleWithProviders {
    return {
      ngModule: MaterialModule,
      providers: [
      ]
    };
  }

}


回答2:

(this is a reproduction of my post here because the two issues are really the same)

I figured out that because MdIconModule itself has MdIconRegistry service in its providers array, every time another module imports it, a new instance of the service is provided. As a result, all components that are loaded at bootstrap time and that belong to the same AppModule share the same instance of this service. However, components loaded later (via lazy-loading) have a different instance of the service and as a result cannot see the icons registered at bootstrap time.

With help from James, I've used the workaround of a specially crafted module that does not use MdIconModule at all, but rather declares the MdIcon class alone. I then provide the MdIconRegistry service separately, and only to the root AppComponent. The result is that there is only one instance of the service app-wide and icons registered at bootstrap time are available everywhere.

Modified MdIconFixedModule

@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,
            //will be available only to whoever calls .forRoot()
            providers: [MdIconRegistry] 
        };
    }
}

Modules that need to just use icons can import MdIconFixedModule as this doesn't contain the MdIconRegistry. The AppModule that also needs to register icons imports MdIconFixedModule.forRoot() which does contain the service.

The details of this implementation can be seen here.

This limitation of ng-Material Modules is slotted to be fixed with the alpha 8 release