I just upgraded from ng2 rc4
with material2 alpha6
to ng2 rc5
with material 2 alpha7-2
. A new error pops up on code that worked before when I use <md-icon>
.
I cannot see the full error text because instead I get Observable_1.Observable.throw is not a function
error (the app crashes), with the top lines in the stacktrace being:
MdIconRegistry.prototype.getNamedSvgIcon
@angular2-material/icon/icon-registry.js:180:16
MdIcon.prototype.ngOnChanges
@angular2-material/icon/icon.js:107:17
If I console.log()
the id of the icon sought just above icon-registry.js @ line 180
, I see ic_lightbulb_outline_24px
. This icon is present in my svg sprite, but it displayed properly before I upgraded today to material 2 alpha 7-2
. Here is its section in the svg sprite:
...<svg viewBox="..." id="ic_lightbulb_outline_24px"><path d="..."/></svg>...
The template:
<md-icon svgIcon="ic_lightbulb_outline_24px"></md-icon>
In my main AppComponent
I have
this._iconRegistry.addSvgIconSet('src/icons/sprite.defs.svg');
I've also imported MdIconModule
into the main AppModule
. What's really puzzling is that
- the same icon from the same sprite file works on other components and
- this worked before the upgrade!
Two more pieces of info:
- this problem only affects lazy-loaded modules
- The same template component with
<md-icon>
will work fine if it's used on the template of a component loaded at app launch, but will fail with this error if it's used on the template of a component that was lazy-loaded
I've built a Plunkr demonstrating the problem. You'll notice that the eagerly loaded components (AppComponent
and HomeComponent
) are able to display the icon. However, LazyLoadedComponent
cannot.
Below is the full stacktrace:
MdIconRegistry.prototype.getNamedSvgIcon /@angular2-material/icon/icon-registry.js:180:16
MdIcon.prototype.ngOnChanges /@angular2-material/icon/icon.js:107:17
anonymous/_View_UserProfileComponent6.prototype.detectChangesInternal@UserProfileComponent.ngfactory.js:1318:29
AppView</AppView.prototype.detectChanges /@angular/core//bundles/core.umd.js:12586:13
AppView</AppView.prototype.detectContentChildrenChanges /@angular/core//bundles/core.umd.js:12604:17
anonymous/_View_UserProfileComponent1.prototype.detectChangesInternal@UserProfileComponent.ngfactory.js:294:3
AppView</AppView.prototype.detectChanges /@angular/core//bundles/core.umd.js:12586:13
AppView</AppView.prototype.detectContentChildrenChanges /@angular/core//bundles/core.umd.js:12604:17
anonymous/_View_UserProfileComponent0.prototype.detectChangesInternal@UserProfileComponent.ngfactory.js:37:3
AppView</AppView.prototype.detectChanges /@angular/core//bundles/core.umd.js:12586:13
AppView</AppView.prototype.detectViewChildrenChanges /@angular/core//bundles/core.umd.js:12612:17
anonymous/_View_UserProfileComponent_Host0.prototype.detectChangesInternal@UserProfileComponent.ngfactory.js:28:3
AppView</AppView.prototype.detectChanges /@angular/core//bundles/core.umd.js:12586:13
AppView</AppView.prototype.detectContentChildrenChanges /@angular/core//bundles/core.umd.js:12604:17
AppView</AppView.prototype.detectChangesInternal /@angular/core//bundles/core.umd.js:12596:13
AppView</AppView.prototype.detectChanges /@angular/core//bundles/core.umd.js:12586:13
AppView</AppView.prototype.detectViewChildrenChanges /@angular/core//bundles/core.umd.js:12612:17
AppView</AppView.prototype.detectChangesInternal /@angular/core//bundles/core.umd.js:12597:13
AppView</AppView.prototype.detectChanges /@angular/core//bundles/core.umd.js:12586:13
AppView</AppView.prototype.detectContentChildrenChanges /@angular/core//bundles/core.umd.js:12604:17
anonymous/_View_AppComponent0.prototype.detectChangesInternal@AppComponent.ngfactory.js:445:3
AppView</AppView.prototype.detectChanges /@angular/core//bundles/core.umd.js:12586:13
AppView</AppView.prototype.detectViewChildrenChanges /@angular/core//bundles/core.umd.js:12612:17
anonymous/_View_AppComponent_Host0.prototype.detectChangesInternal@AppComponent.ngfactory.js:30:3
AppView</AppView.prototype.detectChanges /@angular/core//bundles/core.umd.js:12586:13
ViewRef_</ViewRef_.prototype.detectChanges /@angular/core//bundles/core.umd.js:10804:58
ApplicationRef_</ApplicationRef_.prototype.tick/< /@angular/core//bundles/core.umd.js:10191:79
ApplicationRef_</ApplicationRef_.prototype.tick /@angular/core//bundles/core.umd.js:10191:17
ApplicationRef_/<.next/< /@angular/core//bundles/core.umd.js:10095:103
Zone</ZoneDelegate</ZoneDelegate.prototype.invoke /zone.js/dist/zone.js:323:20
NgZoneImpl/this.inner<.onInvoke /@angular/core//bundles/core.umd.js:9245:36
Zone</ZoneDelegate</ZoneDelegate.prototype.invoke /zone.js/dist/zone.js:322:20
Zone</Zone</Zone.prototype.run /zone.js/dist/zone.js:216:25
NgZoneImpl</NgZoneImpl.prototype.runInner /@angular/core//bundles/core.umd.js:9276:64
NgZone</NgZone.prototype.run /@angular/core//bundles/core.umd.js:9505:55
ApplicationRef_/<.next /@angular/core//bundles/core.umd.js:10095:73
EventEmitter</EventEmitter.prototype.subscribe/schedulerFn< /@angular/core//bundles/core.umd.js:9168:58
SafeSubscriber.prototype.__tryOrUnsub /rxjs/Subscriber.js:225:13
SafeSubscriber.prototype.next /rxjs/Subscriber.js:174:17
Subscriber.prototype._next /rxjs/Subscriber.js:124:9
Subscriber.prototype.next /rxjs/Subscriber.js:88:13
Subject.prototype._finalNext /rxjs/Subject.js:128:13
Subject.prototype._next /rxjs/Subject.js:120:13
Subject.prototype.next /rxjs/Subject.js:77:9
EventEmitter</EventEmitter.prototype.emit /@angular/core//bundles/core.umd.js:9156:58
NgZone</NgZone.prototype._checkStable /@angular/core//bundles/core.umd.js:9415:25
NgZone/this._zoneImpl<.onLeave /@angular/core//bundles/core.umd.js:9387:21
NgZoneImpl/this.inner<.onInvokeTask /@angular/core//bundles/core.umd.js:9239:29
Zone</ZoneDelegate</ZoneDelegate.prototype.invokeTask /zone.js/dist/zone.js:355:24
Zone</Zone</Zone.prototype.runTask /zone.js/dist/zone.js:256:29
ZoneTask/this.invoke /zone.js/dist/zone.js:423:29
Any ideas?
(cross-posted on github)
(this is a reproduction of my post here because the two issues are really the same)
I figured out that because
MdIconModule
itself hasMdIconRegistry
service in itsproviders
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 sameAppModule
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 theMdIcon
class alone. I then provide theMdIconRegistry
service separately, and only to the rootAppComponent
. 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
Modules that need to just use icons can import
MdIconFixedModule
as this doesn't contain theMdIconRegistry
. TheAppModule
that also needs to register icons importsMdIconFixedModule.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.