The structure of my Angular App (and relevant portions) is as follows:
app/app.module.ts
import { DbService } from './db.service'
const APP_CONTAINERS = [
DefaultLayoutComponent,
DefaultHeaderComponent,
];
#NgModule({
declarations: [ ...APP_CONTAINERS ],
providers: [ DbService ]
})
export class AppModule {}
app/containers/default-layout.component.ts
import { Component, HostBinding, Inject } from '#angular/core';
import { DbService } from '../../db.service';
import { navItems } from './_nav';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
#Component({
selector: 'app-dashboard',
templateUrl: './default-layout.component.html'
})
export class DefaultLayoutComponent {
#HostBinding('class.c-app') cAppClass = true;
constructor(private DbService: DbService) {}
async ngOnInit() {
console.log('working')
}
}
I use this same service successfully in other portions of my site but they all have specific module.ts files. I followed the Angular tutorial to get to where I am but I am still getting errors no matter how I try to inject this service.
I also tried using #Inject in my constructor but received the same error.
I currently receive the following error in my console:
ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(e)[e -> e -> e -> e]:
NullInjectorError: No provider for e!
NullInjectorError: R3InjectorError(e)[e -> e -> e -> e]:
NullInjectorError: No provider for e!
I use this same service successfully in other portions of my site but they all have specific module.ts files
So it is unclear how you divide your modules. It doesn't look from the module file like that component is in the module that provides the service. The service has to be in the providers for the injection tree where the component resides. If that module file is for a different module, then the injector has to way to know what you want provided for the service.
One solution would be to add it in the providers for your component. That would get a different instance of the service than in your other modules however:
#Component({
selector: 'app-dashboard',
templateUrl: './default-layout.component.html',
providers: [DbService]
})
export class DefaultLayoutComponent {
You could also add it to the providers for the module your component resides in, but that would get a different instance as well.
I think the best way would be to define the service so that it should be provided in the root module. This way you don't have to add it in the providers anywhere, angular will automatically add it to the root module's providers when it is required. That leads to what Octavian was saying in his comment. I think you just put this code incorrectly in the component instead of the service. Move this to the service and remove the service from the providers arrays in your module(s):
#Injectable({
providedIn: 'root'
})
Related
I am developing an angular library. it has an internal service. which is defined like below.
Used providedIn to be tree-shakable. and didn't use providedIn:'root' because its internal and just used in the module scope.
#Injectable({
providedIn: MyChartModule,
})
export class LineChartLibService {
and when i wanted to add forRoot in module definition to have just one instance in lazy loading, it encounter Circular dependency.
export class MyChartModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: MyChartModule,
providers: [LineChartLibService],
};
}
}
what should we do in this situations?
is it possible to have a lazy load-able tree-shakable service in library?
WARNING: Circular dependency: dist\my-chart\esm2015\lib\my-chart.module.js -> dist\my-chart\esm2015\lib\line-chart\line-chart.component.js
-> dist\my-chart\esm2015\lib\line-chart-lib.service.js -> dist\my-chart\esm2015\lib\my-chart.module.js
I have previously answered a (non-duplicate) question that provides you with alternatives to this approach.
https://stackoverflow.com/a/60377431/5367916
Take this setup:
my-module.ts
declarations: [
MyComponent
]
my-service.ts
#Injectable({ providedIn: MyModule })
my-component.ts
constructor(private myService: MyService) {}
my-service imports my-module
my-module imports my-component
my-component imports my-service
There is a circular dependency.
A workaround
The workaround for this is to create a service module and import that into your module.
my-module.ts
imports: [
MyModuleServices
],
declarations: [
MyComponent
]
my-module-services.ts
// no imports or declarations
my-service.ts
#Injectable({ providedIn: MyModuleServices })
my-component.ts
constructor(private myService: MyService) {}
Alternative
The much more straightforward way is to add the service to your module's providers.
#NgModule({
providers: [ MyService ]
})
export class MyModule {}
I think what happens is the following:
You have the line-chart.component.js that probably calls for the LineChartLibService.
Within the LineChartLibService you say that this Injectable is provided in MyChartModule.
Within the MyChartModule you probably declare the line-chart.component.js to be part of this module.
This means the module asks for the component, which asks for the service, which asks for the module which then asks for the component again: A circular dependency.
If you add more code and context to your question, we might be able to make a better suggestion ;-)
I have an Angular service that looks like this
#Component({})
#Inject(ChromeDataService)
#Injectable()
export class MainDataService {
}
when I run ng build --prod, I get this error
ERROR in : No template specified for component MainDataService
my only guess is that an Angular service does not need to be a component? So I removed the #Component annotation, but then I get this:
ERROR in : Unexpected value 'MainDataService in
/home/.../main.ts'
declared by the module 'SharedModule in
/home/.../src/app/shared.module.ts'.
Please add a #Pipe/#Directive/#Component annotation.
Uh, how do I create a service in Angular5?
To use an angular service properly you only need injectable()
Here's an example
#Injectable()
export class myService {
//some logic
}
then in your app.module or in a feature module you add the service in the providers array and to have the angular DI handle the service for you.
#Component({
usual stuff with template, selector, css})
export class someComponent {
constructor(private myService: MyService){}
}
The constructor will tell angular to auto-magically inject the service you need in.
your service only needs the #Injectable() decorator.like this
import {Injectable} from '#angular/core'
import {Router} from '#angular/router'
#Injectable()
export class AuthService {
constructor(private router: Router) {}
}
That's how I declare services in Angular:
#Injectable()
export class AuthService {
...
}
I think you only need #Injectable decorator. Maybe your problem comes from shared.module.ts.
I have an app with 2 modules so far: "Shared" and "Web".
All my components in web are working fine. I just created a simple component in the Shared module since I plan to re-use it throughout the app:
import { Component, Input, OnInit } from '#angular/core';
#Component({
selector: 'pb-ds-pluginstable',
templateUrl: './pluginstable.component.html',
styleUrls: ['./pluginstable.component.scss']
})
export class PluginstableComponent implements OnInit {
#Input() name: string;
#Input() version: string;
#Input() link: string;
constructor() {}
ngOnInit() {}
}
This is imported into the shared module, and exported:
...other imports...
import { PluginstableComponent } from './pluginstable/pluginstable.component';
#NgModule({
imports: [
CommonModule,
RouterModule,
NgbModule
],
declarations: [HeaderComponent, FooterComponent, HeaderShadowDirective, PluginstableComponent],
exports: [HeaderComponent, FooterComponent, HeaderShadowDirective, PluginstableComponent]
})
export class SharedModule { }
But when I use this in a component's template in the Web module, like this:
<pb-ds-pluginstable name="foo" version="2.2.2" link="bar"></pb-ds-pluginstable>
I get an error that the component is not recognized:
core.es5.js:1020 ERROR Error: Uncaught (in promise): Error: Template parse errors:
'pb-ds-pluginstable' is not a known element:
1. If 'pb-ds-pluginstable' is an Angular component, then verify that it is part of this module.
2. If 'pb-ds-pluginstable' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '#NgModule.schemas' of this component to suppress this message. ("
</section>
[ERROR ->]<pb-ds-pluginstable name="foo" version="2.2.2" link="bar"></pb-ds-pluginstable>
What am I missing here?
You need also to import the SharedModule in that(not parent, not child, exact that module) module, where you want to use it's exported elements
#NgModule({
imports: [
SharedModule,
...
]
})
export class YourModule { }
I asume that you are not importing the shared module into the web module. Most likely you added the import only into the app module
in shared module
you have to export that component.
suppose you have moduleone module which has component componentone you want to add moduleone in shared module moduleshared, which will be added into moduletwo.
I have to export component in moduleshared
that was the problem.
I added my module moduleone in moduleshared but forgot to import, once I added then its available in other component of moduletwo
I have a pages.service.ts
import { Injectable } from '#angular/core';
import { ApiService } from '../../apiService/api.service';
import { Playlists } from '../shared/playlists.model';
#Injectable()
export class PagesService {
private currentPlaylists: Subject<Playlists> = new BehaviorSubject<Playlists>(new Playlists());
constructor(private service: ApiService) {
}
}
This pages service needs another service called ApiService, I inject the way as shown above, it works.
I bootstrap ApiService in main.ts
import { ApiService } from './apiService/api.service';
import { AppComponent } from './app.component';
bootstrap(AppComponent,[
disableDeprecatedForms(),
provideForms(),
HTTP_PROVIDERS,
ROUTER_PROVIDERS,
ApiService
]).catch((err: any) => console.error(err));;
But When I try to inject the PagesService to another component, it gives me error, No Provider for PagesService.
I write that component like this.
import { Component, ViewChild, ElementRef, Input, Output, EventEmitter } from '#angular/core';
import { CORE_DIRECTIVES } from '#angular/common';
import { MODAL_DIRECTVES, BS_VIEW_PROVIDERS } from 'ng2-bootstrap/ng2-bootstrap';
import { ApiService } from '../../apiService/api.service';
import { PagesService } from '../../pages/shared/pages.service';
#Component({
selector: 'assign-playlist-modal',
exportAs: 'assignModal',
providers: [ PagesService ],
directives: [MODAL_DIRECTVES, CORE_DIRECTIVES, FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES ],
viewProviders: [BS_VIEW_PROVIDERS],
styleUrls: ['app/channel/shared/assignPlaylist.css'],
templateUrl: 'app/channel/modals/assignPlaylistModal.html'
})
export class AssignPlaylistModalComponent {
constructor(private apiService: ApiService, private pageService: PagesService, fb: FormBuilder) {
}
}
Update: this is my file structure
channel/
--channel.component.ts
--shared/
----assignPlaylist.modal.ts
----addPlaylist.modal.ts
pages/
--shared/
----pages.service.ts
--pages.component.ts
Channel component is the parent of addPlaylist, addPlaylist is the parent of assignPlaylist. This structure will not work
ChannelComponent
|
AddPlaylistComponent
|
AssignPlaylistComponent ----PagesService----ApiService
I found one solution but don't know why I need to do that,
I add the provider 'PagesService' to ChannelComponent, and also the AssignPlaylistComponent, it will work, no errors.
Even this will work
ChannelComponent ----PagesService-------------
|
AddPlaylistComponent
|
AssignPlaylistComponent ----ApiService---------------
However, I just want to use PagesService in AssignPlaylistComponent, so I think it not make sense to import PagesService in channelcomponent.ts and make a providers array in it.
It is a bit strange, but only components can configure dependency injection in Angular (well, and bootstrap()). I.e., only components can specify providers.
Each component in the component tree will get an associated "injector" if the component has a providers array specified. We can think of this like an injector tree, that is (normally much) sparser than the component tree. When a dependency needs to be resolved (by a component OR a service), this injector tree is consulted. The first injector that can satisfy the dependency does so. The injector tree is walked up, toward the root component/injector.
So, in order for your PagesService to inject a ApiService dependency, that ApiService object first has to be registered with an injector. I.e., in a component's providers array. This registration must occur somewhere at or above the component where you want to use/inject the ApiService .
Your service should then be able to inject the registered ApiService object, because it will find it in the injector tree.
See also Angular 2 - Including a provider in a service.
What I'm trying to do is create a service that uses a model to show an alert. The alert-model should be necessary nowhere else but in that service but I am not able to make this work. My service:
import {Injectable, Inject} from "angular2/core";
import {AlertModel} from "../models/alert.model";
#Injectable()
export class AlertService {
constructor(#Inject(AlertModel) alertModel: AlertModel) {
}
public alert(){
this.alertModel.message = 'success';
//...
}
}
But I keep getting this error:
Uncaught (in promise): No provider for AlertModel! (UserComponent -> AlertService -> AlertModel)
I'm new to angular and I do not understand this. What am I missing? Thanks in advance!
You need to provide the AlertModel somewhere
bootstrap(AppComponent, [AlertModel])
or in the root component (preferred):
#Component({
selector: 'my-app',
providers: [AlertModel],
...
})
Ensure AlertModel has the #Injectable() decorator and all its constructor parameters are provided as well (if it has any)
#Inject(AlertModel) is redundant if the type of the constructor parameter is already AlertModel. #Inject() is only necessary if the type differs or if AlertModel doesn't have the #Injectable() decorator.
constructor(#Inject(AlertModel) alertModel: AlertModel) {
You have this error since there is no provider for the AlertModel class visible from the UserComponent component (that calls the service). You can define either this class in the providers attribute of the component either when bootstrapping your application.
See the question to know more about how hierarchical injectors works and how to inject things into services:
What's the best way to inject one service into another in angular 2 (Beta)?
Since the AlertModel class seems to be a model class I don't think that you need to inject it. You can simply import the class and instantiate it:
#Injectable()
export class AlertService {
alertModel: AlertModel = new AlertModel();
public alert(){
this.alertModel.message = 'success';
//...
}
}