Emit method of EventEmitter not emitting values to subscribers - javascript

So I am trying to connect two components through a service, LoaderComponent and AppComponent with LoaderService, so that when app fetches data a loader shows up. But when I try to use an EventEmitter to emit changes to the components they don't get the changes but when the service subscribes
to itself, it can get the changes
LoaderService.ts
import { EventEmitter, Injectable } from '#angular/core';
#Injectable()
class LoaderService {
#Output change: EventEmitter<number> = new EventEmitter<number>();
private state: number = 0;
constructor() {
this.change.subscribe(state => console.log(state));
this.setState(1)
}
setState(state: number) {
this.state = state;
this.change.emit(this.state);
}
}
// Shows state when but outside of the service event is not detected, also tried EventEmitter from from events
I expect to get events from the LoaderService to subscribers

You need to use LoaderService in some component for angular to create it, if we do not use the service any where angular will automatically discard it. Inject LoaderService in app component like below:
constructor(private _loadService: LoaderService) {} and then you will see the console.log().
Also, it is recommended to use either Subject or Behavior Subject from Rxjs instead of Output in a service.

First thing, EventEmitters and Outputs don't belong in a service.
I will refactor to use subjects and also protect your subject by making it private and exposing a public observable, this limits how your subject state can be modified, this is not required but is generally considered good practice:
import { Injectable } from '#angular/core';
import {Subject} from 'rxjs/Subject';
import {Observable} from 'rxjs/Observable';
#Injectable()
class LoaderService {
private change: Subject<number> = new Subject<number>();
change$: Observable<number> = this.change.asObservable();
private state: number = 0;
constructor() {
this.change$.subscribe(state => console.log(state));
this.setState(1)
}
setState(state: number) {
this.state = state;
this.change.next(this.state);
}
}
Second, this is likely an issue with how you provide your service. If you have an app component template like:
<loader-component></loader-component>
<loader-component></loader-component>
with 2 loader components side by side, and the loader component has a providers array like:
providers: [LoaderService]
then these 2 loaders are receiving different copies of the same service as they each provide and inject their own, so they will not see each other's events.
To remedy this, you provide instead in the app component (and not in the loader component) so they have the same copy of the service, because then the parent is providing the service that each of them inject. If you were to provide in both app component and loader component, they would all receive a different copy.
If you provide at root (module level) then every component that injects the service (and doesn't provide it's own) will receive the same copy of that service.
The appropriate place to provide a service is dependent on your app's needs and the function of the particular service.

Related

How to use same instance of service in pop up window?

I am trying to use a communication service to send some data between different angular components. But I am facing an issue when the child component is opened inside a pop-up window. Since it is a separate angular app itself. So it's taking a different instance of the service and thus I am unable to send data.
This is my communication Service.
import { Injectable } from "#angular/core";
import { Subject } from "rxjs";
#Injectable()
export class CommunicatingService {
private subject = new Subject<any>();
sub = this.subject.asObservable()
constructor() {}
nextSub(data: any) {
this.subject.next(data)
}
}

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)

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.

Subject in RxJs and EventEmitter in Angular2

What's the difference between them, when and how to use them? I read that Subject is the equivalent to an EventEmitter.
If I want to rewrite this, how?
import { Injectable} from '#angular/core';
import { Subject,BehaviorSubject } from 'rxjs';
import {Playlists} from 'channel' /** Assumes this is where you have defined your Playlists interface **/
#Injectable()
export class PlaylistService {
private _currentPlaylists$: Subject<Playlists> = new BehaviorSubject<Playlists>(null);
constructor() {}
currentPlaylists() {
return this._currentPlaylists$.asObservable();
}
setCurrentPlaylists(playlists:Playlists){
this._currentPlaylists$.next(playlists);
}
}
EventEmitters should be used only when implementing custom events in Angular2 components with the Output decorator:
#Output()
someEvent: EventEmitter = new EventEmitter();
In other cases, you can use Subjects (from Rxjs) since it's not related to Angular2 particular feature.
EventEmitter internally extends Subject. See https://github.com/angular/angular/blob/master/modules/%40angular/facade/src/async.ts#L63
Your code looks good to me ;-)

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

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

Categories

Resources