I have a component that uses a service. The component looks something like this:
#Component({
moduleId: module.id,
selector: 'test',
providers: [HTTP_PROVIDERS, TestService]
})
export class TestComponent implements OnInit {
constructor(private _testService:TestService) {
}
As you can see, I added the HTTP_PROVIDERS provider in my component. This worked since the DI is now aware of the http classes. However, it was my TestService that was really using the Http class, not my TestComponent.
#Injectable()
export class TestService {
constructor(private _http:Http) {
}
I felt that since it is the service using the Http class, it should be the one including the providers in itself. The TestComponent wouldn't know what providers TestService would need.
Since the service class doesn't have that component decorator, I'm not sure how I can actually add providers to it. How can I add providers to a Service class?
What you can do is,
Inject HTTP_PROVIDERS into bootstrap function ,
import {HTTP_PROVIDERS} from '#angular/http';
bootstrap(AppComponent,[HTTP_PROVIDERS]);
and in your service,
import {Http} from '#angular/http';
#Injectable()
export class TestService {
constructor(private _http:Http) {}
}
Related
Imagine we have this component structure:
app1
-- app1.component.html
-- app1.component.ts
parent1
parent2
app2
-- app2.component.html
-- app2.component.ts
How could I reuse the app2 component in the app1? For example, reuse a table (both HTML and logic on typescript) instead of copy and paste code.
I have searched for solutions like ng-template, but failed. Also, call the tag didn't work as well.
If the tag didn't work inside app1 I assume that you are importing app2 component inside another module. If we want to use component over multiple modules you need to import app2 ONLY in shared module then import that module to modules where you want to have that component.
Make sure to export that component inside shared module.
Need to use componentFactoryResolver https://angular.io/guide/dynamic-component-loader
For example you want to use ThirdComponent inside FirstComponent
//HTML
<section #firstComp></section>
//TS
import { AfterViewInit, Component, ComponentFactoryResolver, OnInit, ViewChild, ViewContainerRef } from '#angular/core';
import { ThirdComponent } from '../third/third.component';
#Component({
selector: 'app-first',
templateUrl: './first.component.html',
styleUrls: ['./first.component.scss']
})
export class FirstComponent implements OnInit, AfterViewInit {
#ViewChild('firstComp',{read: ViewContainerRef}) firstComp: ViewContainerRef;
constructor(
private componentFactoryResolver: ComponentFactoryResolver
) { }
ngOnInit(): void {
}
ngAfterViewInit() {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(ThirdComponent);
const componentRef = this.firstComp.createComponent<ThirdComponent>(componentFactory);
}
}
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 a service:
#Injectable()
export class MyService implements IMyService {
myServiceArray: Array<string> = ["hi", "hello", "yoyo"];
}
This Service is injected in a Component that updates the array of string with ngModel. When I try to print the array from the Component or from the Service everything is working fine (aka the array is updated with the ngModel).
I also #Inject such Service in another 1.
#Injectable()
export class AnotherService implements IAnotherService {
constructor(public myService: MyService) {
}
printValues() {
console.log(this.myService.myServiceArray);
}
}
When I call printValues(), ["hi", "hello", "yoyo"] is printed even if I updated the values of the array with a model!
What am I doing wrong?
EDIT:
The code of the component is the following.
#Component({
selector: 'app-root',
providers: [MyService],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppCustomerData implements IAppCustomerData {
constructor(public myService: MyService) {
}
}
You have to look that you inject the same instance of the service, if you have multiple instances of the service each one has a own array in it.
I would try to use the local storage to store the data in the service, than you can have multiple instances and each one can edit or return the same value:
How to store token in Local or Session Storage in Angular 2?
Maybe this answers your problem:
How do I create a singleton service in Angular 2?
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';
//...
}
}