Angular2: Service with Model - "no provider for model" - javascript

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';
//...
}
}

Related

how to share objects between sibling components using services?

I need to call a service on a component, and ideally this service would fetch info in another 2 or 3 components (which already are communicated with the database, etc). I need to be able to share objects.
I've created a service called DashService, like this:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root',
})
export class DashService {
constructor() { }
}
I've linked it to the component that will us it, and I also imported and added the service name in the 'providers' part of the NgModule.
Added:
Import { OnInit } from '#angular/core';
and
implements OnInit{...}
on the module that will send info to the service.
I dont know how to go forward. How can I share an object that exists on a component, to my service? I fail to set the Constructor correctly (on the component sending the info)
When I try
public constructor( private DashService: DashService)
I get an error telling me 'DashService refers to a value but is being used as a type'
Thank you for your help.
Because you are calling the service as the type of the service!
Just change the name, usually the first letter of the service is in lowercase
public constructor( private dashService: DashService)
https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service
here you can find an example how to communicate between components.In general for parent/child components you can use #Input / #Output decorator.
For others case you can use a service ( or a any state management)
Riccardo Gai is right, you should do that to use a service,
public constructor( private dashService: DashService)
But to answer your question, in order to be able to share data between components through a service, you should create an object in that service, for example a public object, then you can access that object through the service.
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root',
})
export class DashService {
objectToShareHere: any;
constructor() { }
}
I think anyway, the best way of this to work is to have get and set methods and access the object through them (having a private obj). Like this:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root',
})
export class DashService {
private objectToShareHere: any;
constructor() { }
setPrivateObj(obj) {
this.objectToShareHere = obj;
}
getPrivateObj() {
return this.objectToShareHere;
}
}
If the data you need to share is from a BE, you can use a Subject object (see RxJs subject here)

How to use composition instead of inheritance when sharing logic between components in Angular 6?

I have a module in Angular that is structured likes this:
moduleName
componentA
componentB
Now componentA and componentB are very similar, as they share some attributes and methods, e.g.:
protected available: boolean = true;
As I don't want to repeat myself, I've created a base class, that stores all this:
export abstract class BaseComponent {
protected available: boolean = true;
}
And both controllers inherit from that class:
import { BaseComponent } from '../base.component';
export class ComponentA extends BaseComponent implements OnInit {
constructor() {
super();
}
ngOnInit() {
console.log(this.available);
}
}
This works just fine. However, when I research this soultion a lot of people are saying:
Don't use inheritance, use composition in this case.
Alright, but how can I use composition instead? And is the gain really that big over the current solution?
Thanks a lot for your time.
For composing objects in angular you need to have a reference to that object inside of your class, which shares data and functionality. To do that you need to use Angular services, and inject them to your class, and there should be 1 instance of service per component.
Create a new service by running ng g s my-service, remove providedIn: 'root' from your service annotation (We want to provide instance per component)
Add public available: boolean = true; to the service
provide the service through the components, in #Component configs on your components
inject the service in your both component constructors, constructor(private myService:MyService)
Now you have a composition that keeps data and functionality
#Component({
selector: 'app',
templateUrl: './app.my-component.html',
styleUrls: ['./app.my-component.css'],
providers: [MyService]
})
export class MyComponent {
constructor(private myService: MyService) {
}
}
If you create same components with big part same logic. you can use inheritance for example controlSelectComponent and controlInputComponent stackblitz example
For composition you need to create service and provide it to both components. But you dont keep component state in service becose all service are singletone. And when one component change state another component crash.
You also can provide service to each component in providers section
#Component({
selector: 'app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [MyService]
})
export class AppComponent {
constructor(private myService: MyService) {
}
}
But in case with saving state in service is not the best solution
Conclusion
Use services and composition for share helper methods between components.
Use abstract class and inheritance for components with same logic and state changes.
I would also recommend to read about Composition over Inheritance. The syntax(InversifyJs) is very similar that Angular uses. Please see this blog

How to declare a service with Angular5

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.

Angular: call function from other component

I'm trying to make two angular components and I want to call a function from the first component in the second component. When I try this I get following error message: Cannot red property 'functionName' of undefined. How can this be solved?
Here a link of an example: https://stackblitz.com/edit/angular-rre4gb
That's because the component you want to call its function, is not instantiated.
for component communication you can use a service instead:
Service
#Injectable()
export class MyService {
myCustomFunction(){
}
}
Component
in your component:
#Component({
selector: 'my-component',
providers: [ MyService ]
})
export class MyComponent {
// inject your service to make it available
constructor(private service: MyService){}
doStuff(){
// call function which is located in your service
this.service.myCustomFunction();
}
}
As others have stated, I would prefer a shared service with a Subject among these components.
service:
#Injectable()
export class SharedService {
mySubject = new Subject();
}
WorldComponent (subscriber):
export class WorldComponent {
constructor(private sharedService: SharedService){
this.sharedService.mySubject.subscribe((data)=>{
this.worldFunction();
})
}
HelloComponent(publisher):
public helloFunction() {
alert('Hello');
this.sharedService.mySubject.next(true);
}
You can find the updated example here: https://stackblitz.com/edit/angular-rnvmkq?file=app%2Fworld.component.ts
The best way to share information between multiple components is generally through a service.
Create a separate file: file.service.ts
Provide the service in the app.module.ts file
Inject the service into each component. Then you'll have access to the variables in both components
See this: https://angular.io/tutorial/toh-pt4
the reason of the error is that the hello component is not imported, but instead of calling a component from another, you should use a service in between, as other answers already suggested.

Inserting multiple services into a service - angular2

I am trying to inject a self created service & the angular2 Http service into my custom HttpRest service.
using
#Inject(Http) public _http: Http
worked fine, but when I try to inject another self made service i get following Error:
EXCEPTION: Cannot resolve all parameters for 'HttpRest'(Http #Inject(Http), undefined #Inject(undefined)). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'HttpRest' is decorated with Injectable.
For some reason
UserIds is undefined, even though the import is succesful.
My custom service:
#Injectable()
export class UserIds{
private _signature_id:string;
private _role_id:number;
get signature_id():string{
return this._signature_id;
}
set signature_id(id:string){
this._signature_id = id;
}
get role_id():number{
return this._role_id;
}
set role_id(id:number){
this._role_id = id;
}
}
The Custom HttpRest service im injecting both Http & UserIds into:
#Injectable()
export class HttpRest{
groups;
constructor(
#Inject(Http) public _http: Http,
#Inject(UserIds) public _ids: UserIds
){}
...
}
NOTE! when I remove
,
#Inject(UserIds) public _ids: UserIds
I dont get the Error.
What am I missing ?
UPDATE
The problem is actually that UserIds is undefined in the constructor params for some unknown reason that im trying to understand, so the title of this question becomes irrelevant. It should be "Imported service is undefined in constructors params".
Please reffer to my answer on this question further down this post.
UPDATE:
Please reffer to a question that discusses this issue.
Using index.ts file to export class causes undefined in injected constructor
#Inject(...) in #Inject(Http) public _http: Http is redundant when the parameter to #Inject() is the same as the type of the parameter.
#Injectable()
export class HttpRest{
groups;
constructor(public _http: Http, public _ids: UserIds
){}
...
}
You need to provide Http and UserIds so DI is able to resolve the dependency. Http is included in HTTP_PROVIDERS
#Component({
selector: '...',
providers: [HTTP_PROVIDERS, UserIds],
template: ...
})
export class AppComponent {
}
Ensure you have everything imported correctly
import {HTTP_PROVIDERS, Http} from 'angular2/http';
Ok so I found the problem, and it has not to do with Inject.
The problem was that im using an index file to export services, as mentioned in the angular 2 style guide (https://github.com/mgechev/angular2-style-guide/blob/master/old/README.md#directory-structure), and for some reason importing this specific service from the index causes an undefined value when injected into the constructor.
When I reffernced the source directly and not trough the index file, for some reason that is unknown to, resolved the Error.
The import before the fix looked like this:
import {UserIds} from "../index";
Which worked with all other services and components.
The import using the direct source file:
import {UserIds} from "../user_ids/user_ids.service";
For some reason this solved my problem, but i want to stay consistent with the index.ts encapsulation.
If anyone has an idea why this could happen I'll be happy for updates.
You need to register your UserIds service at the root level (main.ts) or in the app.component.ts, which is the highest level in the hierarchy:
#Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>',
providers: [ UserIds ]
})
export class AppComponent { }

Categories

Resources