John Dibling John Dibling - 16 days ago 6
TypeScript Question

No provider for shared component

My app has several feature modules which use a few common

@Component
s. So I wwas trying to move all those shared components in to a 'Widget Module` as described by the angular.io FAQ linked here.

However when I try to add this widget to one of my templates, I'm getting:

Error in package:./src/app/tracker/clients/client-detail.component.ts
class ClientDetailComponent - inline template:28:8 caused by:
No provider for String!


Here is where I try to use that shared component within the feature module:

@Component({
moduleId: module.id,
selector: 'client-detail',
template: `
<save-button id="save-button" (click)="saveClient()" [isSaving]="isSaving" [disableSave]="disableSave"></save-button>
`
})
export class ClientDetailComponent implements OnInit {
isSaving: boolean = false;
disableSave: boolean = false;

constructor() { }

ngOnInit() {}

saveClient() {
this.isSaving = true;
// do some work...
this.isSaving = false;
}


Here's the feature module module:

import {SharedWidgetModule} from "../shared/shared-widget.module";

@NgModule({
imports: [
CommonModule,
FormsModule,
TrackerRoutingModule,
SharedWidgetModule
], declarations: [
TrackerComponent,
TrackerHomeComponent,

// Clients
ClientsComponent,
ClientsHomeComponent,
ClientShieldComponent,
ClientDetailComponent,

// EndClients
EndClientListComponent
], providers: [
BackendService,
ClientsService
]
})
export class TrackerModule { }


The
<save-button>
component comes from the SharedWidgetModule:

import {NgModule} from "@angular/core";
import {SaveButtonComponent} from "./save-button/save-button.component";
import {CommonModule} from "@angular/common";

@NgModule({
imports: [CommonModule],
exports: [SaveButtonComponent, CommonModule],
declarations: [SaveButtonComponent],
providers: [],
})
export class SharedWidgetModule { }


save-button.component.html:

<button type="submit" class="btn btn-primary" [disabled]="disableSave || isSaving">
<i *ngIf="isSaving" class="fa fa-refresh fa-spin"></i>
<i *ngIf="!isSaving" class="fa {{icon}}"></i>
{{name}}
</button>


save-button.component.ts:

import {Component, OnInit, Input} from "@angular/core";

@Component({
moduleId: module.id,
selector: 'save-button',
templateUrl: 'save-button.component.html',
styleUrls: ['./save-button.component.scss']
})
export class SaveButtonComponent implements OnInit {
name: string;
icon: string;
@Input() isSaving: boolean;
@Input() disableSave: boolean;

constructor(name: string, icon: string) {
this.name = name || 'Save';
this.icon = icon || 'fa-floppy-o';
}

ngOnInit() { }
}


What am I doing wrong?

Answer

Your problem lies on the constructor of SaveButtonComponent. For those Angular2 elements (Component, Directive, Injectable, etc.), constructor is a sacred place that should not be contaminated by mere primitives. Put it another way, Angular2 will try to inject services to your components using the information in its constructor, and clearly name and icon are not services.

I see that you are not using them at the moment, why don't you just get rid of those primitives and leave your SavebuttonComponent.constructor() empty? You can always set them up at later stage.

Comments