Reputation: 61
I am working on an Angular 7 app. I have a lot of cross-component communication happening in my project, and the components do not have a parent-child relationship.
As I know a good solution for such problems are services. Can I have a single service that handles all communication app-wide(information will be very different) or do I have to write a different Service for each pair of components? That seems like a lot of repeated code. Otherwise, if used in each component that needs to send or receive information, on each subscribe it will actually subscribe to all the information ever sent through this service which is definitely not the desired behavior.
My service looks like this:
@Injectable({providedIn: 'root'})
export class ComponentService {
private subject = new Subject<any>();
sendData(data: any) {
this.subject.next(data);
}
getData(): any {
return this.subject.asObservable();
}
}
Information is sent like this:
this.componentService.sendData(element);
And is received in another component like this:
constructor(private componentService: ComponentService) {
}
ngOnInit() {
this.componentService.getData().subscribe(data => data);
}
Obviously, if ComponentService is used all over the app, this will make all components(that communicate to others) subscribe to information they do not expect to receive, and do not need to receive. What approach should be used?
Upvotes: 3
Views: 292
Reputation: 11162
Technically you could have a single service with a Subject that emits an object with a property that determines what type of data it is, like:
{ type: 'CustomerId', value: 35 }
However, you won't benefit from TypeScript's type-hinting. The good thing about TypeScript is that you can declare a type alias/interface (like CustomerData
) and then have a typed subject that emits this data:
private subject: Subject<CustomerData> = new Subject<CustomerData>();
When you subscribe to this subject in a component, you will have a typed result, instead of the any
type, which should be used as sparringly as possible (or never).
If you're concerned with code duplication you could make an abstract generic base service and have your other services extend it:
@Injectable({providedIn: 'root'})
export abstract class BaseComponentService<T> {
private subject = new Subject<T>();
sendData(data: T) {
this.subject.next(data);
}
getData(): any {
return this.subject.asObservable();
}
}
So when you create new services you extend the class with a defined type:
type SubType = {
name: string;
age: number;
};
@Injectable()
export class SubService extends BaseComponentService<SubType> {
}
Upvotes: 1