Angular 2 - No provider for Service - dependency-injection

I've been trying to troubleshoot a strange problem with angular 2 where it isn't detecting my provider declaration, but nothing is working. I can't even replicate it in plunkr.
I'm using angular 2 rc 3 with router 3.0 alpha.8.
Error message is: ORIGINAL EXCEPTION: No provider for TestService!
app.routes.ts:
import { provideRouter, RouterConfig } from '#angular/router';
import { HomeComponent } from './app/home/home.component';
import { LogInComponent } from './app/log-in/log-in.component';
import { SignUpComponent } from './app/sign-up/sign-up.component';
export const routes: RouterConfig = [
{ path: '', component: HomeComponent },
{ path: 'log-in', component: LogInComponent },
{ path: 'sign-up', component: SignUpComponent }
];
export const APP_ROUTER_PROVIDERS = [
provideRouter(routes)
];
main.ts:
import { bootstrap } from '#angular/platform-browser-dynamic';
import { enableProdMode } from "#angular/core";
import { AppComponent } from './app/app.component';
import { APP_ROUTER_PROVIDERS } from './app.routes';
// enableProdMode();
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS
])
.catch(error => console.log(error));
app/app.component.ts:
import { Component } from '#angular/core';
import { ROUTER_DIRECTIVES } from '#angular/router';
import { TestService } from './shared/test.service';
#Component({
selector: 'my-app',
template: `
<div id="menu">
<a [routerLink]="['/sign-up']"><button>Sign Up</button></a>
</div>
<router-outlet></router-outlet>
`,
directives: [ROUTER_DIRECTIVES],
providers: [TestService]
})
export class AppComponent {
constructor() { }
}
app/sign-up/sign-up.component.ts:
import { Component } from '#angular/core';
import { ROUTER_DIRECTIVES } from '#angular/router';
import { TestService } from '../shared/test.service';
#Component({
selector: 'sign-up',
template: `<h1>Sign up!</h1>`,
directives: [ROUTER_DIRECTIVES]
})
export class SignUpComponent {
constructor(private testService: TestService) {
this.testService.test('works?');
}
}
app/shared/test.service.ts:
import { Injectable } from '#angular/core';
#Injectable()
export class TestService {
constructor() { }
test(message: string) {
console.log(message);
}
}
So, I'm providing the testservice in the base component (app.component.ts) because I want all my components to access the same instance. However, when I navigate to sign-up, I get the no provider for testservice error. If I provide the TestService within the sign-up component, this then works:
import { Component, OnInit } from '#angular/core';
import { ROUTER_DIRECTIVES } from '#angular/router';
import { TestService } from '../shared/test.service';
#Component({
selector: 'sign-up',
template: `<h1>Sign up!</h1>`,
directives: [ROUTER_DIRECTIVES],
providers: [TestService]
})
export class SignUpComponent implements OnInit {
constructor(private testService: TestService) { }
ngOnInit() { }
}
However, I need the same instance accessible throughout my app, so how can I inject this at the main component level?
I even tried replicating this app-level service providing with plunkr with the same version of everything, but it doesn't seem to give me the same error...
http://plnkr.co/edit/5bpeHs72NrlyUITCAJim?p=preview

Injecting something on the app level is done in bootstrap:
main.ts:
import { TestService } from '../shared/test.service';
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS, TestService
])

For me, some references to the "services" folder were "Services". When I made them all "services" (lower case), it worked.
For example:
import {ApiService} from "./Services/api.service";
didn't work, but this worked:
import {ApiService} from "./services/api.service";

To All future readers - and this is correct for angular 2.0.0 rc-4:
make sure that you follow the below folder structure:
root:
index.html
package.json
systemjs.config.js
tsconfig.json (if using TypeScript)
typings.json
app (folder):
- main.js (the root script for your app)
- app.component.js (the root component for the entire app)
This is crucial for the hierarchical injection to properly scope and identify providers.
Also, and this is very important - if still encountering problems and you are using TypeScript or any other transpiled language- delete any artifacts which your transpiler produces for every associated class in the problematic object graph - this, and the OP's answer eventually helped in my case (*.map.js and *.js files deleted and re-transpiled).

It was a configuration issue after all, and a completely elusive one at that.
Per the ang2 style guide, I had my main.ts one folder up from my main app folder, and in systemjs.config I had to declare the main for app as '../main.js'. When I moved the main file to the root app folder and changed the package declaration in systemjs to 'main.js' it worked.
The odd thing is everything else worked, right up until I try to utilize hierarchical dependency injection.

Related

angular7 WARNING in Circular dependency detected:

I am trying to register a service toa specific module with the help of 'provideIn' attribute in my angular7 app.
test.module.ts
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { TestComponent} from './test.component'
#NgModule({
declarations: [TestComponent],
imports: [
CommonModule
],
exports: [TestComponent]
})
export class TestModule { }
test.component
import { Component, OnInit } from '#angular/core';
import { TestServiceService } from '../test-service.service';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
constructor(public service: TestServiceService) { }
ngOnInit() {
}
}
test-service.ts
import { Injectable } from '#angular/core';
import { TestModule } from './test/test.module';
#Injectable({
providedIn: TestModule
})
export class TestServiceService {
val = 3;
constructor() { }
getDetails() {
return this.val;
}
}
when I run my app it shows below error
ERROR Error: Uncaught (in promise): Error: StaticInjectorError(AppModule)[TestComponent -> TestServiceService]:
StaticInjectorError(Platform: core)[TestComponent -> TestServiceService]:
NullInjectorError: No provider for TestServiceService!
when I change provideIn atrribute value as 'root' everything works fine.How can I register a service to specific module with the help of 'provideIn' attribute in angular7?
TestService has to be depend on TestModule in order to use providedIn to provide the service to the module. This creates a circular dependency, because TestModule has to depend on TestComponent which depends on TestService. Define the provider in the module so that the module depends on the component and the service.
#NgModule({
declarations: [TestComponent],
imports: [
CommonModule
],
providers: [
TestService
],
exports: [TestComponent]
})
export class TestModule { }
Define the service as Injectable, and set providedIn to null.
#Injectable({
providedIn: null
})
export class TestServiceService {
val = 3;
constructor() { }
getDetails() {
return this.val;
}
}
Change test.component to this :
import { Component, OnInit } from '#angular/core';
import { TestServiceService } from '../test-service.service';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss'],
providers : [TestServiceService]
})
export class TestComponent implements OnInit {
constructor(public service: TestServiceService) { }
ngOnInit() {
}
}
and if you want to have single instance of service in module change test.module.ts to this :
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { TestComponent} from './test.component'
#NgModule({
declarations: [TestComponent],
imports: [
CommonModule
],
providers :[TestServiceService ],
exports: [TestComponent]
})
export class TestModule { }
do one of them

Angular 6+ providedIn: 'root' raising a StaticInjectorError

I have googled extensively and I can't seem to find anyone else with this issue, so I must be missing something. I am converting all of my AppModule services to use the providedIn: 'root' method, but it doesn't seem to be working.
import { Injectable } from '#angular/core';
Injectable({
providedIn: 'root'
})
export class CommonService{
UserName : string = 'Guest';
Roles : Array<any> = [];
Theme: string = 'standard';
constructor(){}
}
Here is one of the components that uses the service:
import { CommonService } from './Services/common.service';
#Component({
selector: 'navBar',
templateUrl: './navbar.html'
})
export class NavBar {
constructor(private session: CommonService) {}
At runtime, this is the error in the console:
StaticInjectorError(AppModule)[NavBar -> CommonService]:
StaticInjectorError(Platform: core)[NavBar -> CommonService]:
NullInjectorError: No provider for CommonService!
I've checked the documentation, and I don't see where I am going wrong. What am I missing?
Forgot to mention, NavBar is a component declared in SharedModule, SharedModule is imported in AppModule.
You may be missing the leading "#" on Injectable:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class CommonService{
UserName : string = 'Guest';
Roles : Array<any> = [];
Theme: string = 'standard';
constructor(){}
}
There may not be an error in the IDE, but that looks like it might be the issue

How to instantiate/inject class declared in main component to another component

My AppComponent sample:
///other imports here
import { ApplyColor } from './../../shared/directives/applycolor';
import { SomeComponent} from './../../components/somecomponent';
#Component({
selector: 'my-app',
directives: [ApplyColor, ROUTER_DIRECTIVES],
providers: [ROUTER_PROVIDERS],
templateUrl: 'myurl.html'
})
#RouteConfig([
//routes here
{ path: '/main', name: 'Main', component: SomeComponent, useAsDefault: true },
])
export class AppComponent {
}
In order to instantiate ApplyColor in SomeComponent
Import ApplyColor
Add to directives: [ApplyColor]
Instantiate with a new keyword
Which is:
import {Component, AfterViewInit, ViewChild} from 'angular2/core';
import { ApplyColor } from './../../shared/directives/applycolor';
#Component({
selector: 'my-selector',
directives: [ApplyColor],
templateUrl: 'app/components/mycomponenturl.html'
})
export class MyComponent implements AfterViewInit {
constructor() { }
ngAfterViewInit() {
var color = new ApplyColor();
color.apply(2);
}
}
How can I instantiate/inject ApplyColor without there 3 steps above?
Directive instances are managed by Angular2. This means that you only need to specify it into the directives attribute. So if ApplyColor is a directive just add it into the directives attribute.
If ApplyColor isn't a directive, you can explicitly instantiate into the provide to the child component using #Input.
In your case, it's a bit particular since you leverage routing. In this case, you need to rely on a shared service. Such service needs to be defined when bootstrapping the application to be able to share a single instance for all components. You can set your instance of ApplyColor into a field of this service. So both component (AppComponent and SomeComponent) can access it.
Define the service
export class SharedService {
color:ApplyColor;
}
Bootstrapping the service
bootstrap(AppComponent, [ SharedService ]);
Set color from AppComponent
#Component({
(...)
})
export class AppComponent {
constructor(private service:SharedService) {
var color = new ApplyColor();
this.service.color = color;
}
}
Get color from SomeComponent
#Component({
(...)
})
export class AppComponent {
constructor(private service:SharedService) {
this.service.color.apply(2);
}
}
I have just started working angular2 but as I can understand:
import ApplyColor => you can't remove that, it required by the compiler to know which class you are referenced to
directives : [ApplyColor] => that means you will use the selector (the one you have defined in applycolor.ts) in the template (app/components/mycomponenturl.html). it is only to know where the component will be in the view.
new ApplyColor => you are creating the object yourself, it is not injected.
To inject your component,
export class MyComponent implements AfterViewInit {
constructor(private color:ApplyColor) { }
ngAfterViewInit() {
this.color.apply(2);
}
}
I hope it helped you ?

Visual Studion 2015 and Angular2 Beta 2 dependency injection

My environment is VS2015 with TypeScript 1.7.3, Angular2 Beta 2, target ECMA 5. I've modified the csproj file to include TypeScriptExperimentalDecorators = true.
I'm working on the Angular2 tutorial and can not get dependency injection working as documented. I can only get DI to work when I include #Inject in the AppComponent class constructor. If I don't include #Inject I receive this error -
EXCEPTION: Cannot resolve all parameters for AppComponent(?). Make sure they all have valid type or annotations.
I did not include the code in this post because its the same as the tutorial. I did try modifying boot.ts as follows:
bootstrap(AppComponent, [HeroService]);
but I still get the error. Has anyone else run into this?
The HeroService is decorated with #Injectable:
import {Hero} from './hero';
import {HEROES} from './mock-heroes';
import {Injectable} from '../node_modules/angular2/core';
#Injectable()
export class HeroService {
heroes: Hero[];
getHeroes() {
return Promise.resolve(HEROES);
}
// See the "Take it slow" appendix
getHeroesSlowly() {
return new Promise<Hero[]>(resolve =>
setTimeout(() => resolve(HEROES), 2000) // 2 seconds
);
}
}
app.component.ts
import {Component, OnInit, Inject} from '../node_modules/angular2/core';
import {Hero} from './hero';
import {HeroDetailComponent} from './hero-detail.component';
import {HeroService} from './hero.service';
#Component({
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="#hero of heroes"
(click)="onSelect(hero)"
[class.selected]="hero === selectedHero">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
`
,directives: [HeroDetailComponent]
,providers: [HeroService]
})
export class AppComponent implements OnInit {
public title = 'Tour of Heroes';
public heroes: Hero[];
public selectedHero: Hero;
constructor(private _heroService: HeroService) {
// constructor( #Inject(HeroService) private _heroService: HeroService) {
}
getHeroes() {
this._heroService.getHeroes().then(heroes => this.heroes = heroes);
}
ngOnInit() {
this.getHeroes();
}
onSelect(hero: Hero) { this.selectedHero = hero; }
}
I solved the problem by adding the following to the csproj file and was able to remove the #Inject from the code -
<TypeScriptEmitDecoratorMetadata>true</TypeScriptEmitDecoratorMetadata>
See here for how to set TS compiler options in Visual Studio

How to use angular2 DynamicComponentLoader in ES6?

I'm not using typescript but ES6 and angular2 alpha39 to load a component dynamically. The following code is similar to what I have in my app. What I have noticed is angular2 does not create an instance of DynamicComponentLoader nor ElementRef and inject into the constructor. They are undefined.
How can I do the injection of DynamicComponentLoader using ES6 and angular2 alpha39?
import {Component, View, Inject, DynamicComponentLoader, ElementRef } from 'angular2/angular2'
#Component({
selector: 'dc',
bindings: [ DynamicComponentLoader ]
})
#View({
template: '<b>Some template</b>'
})
class DynamicComponent {}
#Component({
selector: 'my-app'
})
#View({
template: '<div #container></div>'
})
#Inject(DynamicComponentLoader)
#Inject(ElementRef)
export class App {
constructor(
dynamicComponentLoader,
elementRef
) {
dynamicComponentLoader.loadIntoLocation(DynamicComponent, elementRef, 'container');
}
}
If you want to write code in ES7, I think the most concise approach to specify injections at this time is to use static getter for parameters:
import {Component, View, DynamicComponentLoader, ElementRef } from 'angular2/angular2'
#Component({
selector: 'my-app'
})
#View({
template: '<div #container></b>'
})
export class App {
static get parameters() {
return [[DynamicComponentLoader], [ElementRef]];
}
constructor(dynamicComponentLoader, elementRef) {
dynamicComponentLoader.loadIntoLocation(DynamicComponent, elementRef, 'container');
}
}
See this plunker
If you want to write code in ES6, which doesn't support decorators, you must also use static getter for annotations property. In this case you must import ComponentMetadata and ViewMetadata instead of Component and View For example:
import {ComponentMetadata, ViewMetadata, DynamicComponentLoader, ElementRef } from 'angular2/angular2';
export class App {
static get annotations() {
return [
new ComponentMetadata({
selector: 'app'
}),
new ViewMetadata({
template: '<div #container></b>'
})
];
}
static get parameters() {
return [[DynamicComponentLoader],[ElementRef]];
}
constructor(dynamicComponentLoader, elementRef) {
dynamicComponentLoader.loadIntoLocation(DynamicComponent, elementRef, 'container');
}
}
See this plunker

Resources