Reputation: 571
Given a basic type
export interface Item {
id: string;
}
I define a class BackupClient
with a Subject
:
export class BackupClient {
private subject = new Subject<Item>();
private share(item: Item): void {
this.subject.next(item);
}
public subscribe(observer?: Partial<Observer<Item>>): Subscription {
return this.subject.subscribe(observer);
}
}
Via the BackupService
a component ItemComponent
may subscribe to my BackupClient
and update its item
whenever BackupClient
shares a new item
.
import { BackupClient } from './backup.client';
import { Injectable } from '@angular/core';
@Injectable()
export class BackupService {
constructor() {}
public client = new BackupClient();
}
import { BackupService } from '../backup.service';
import { Component, Input } from '@angular/core';
import { Item } from '../item';
@Component({
selector: 'app-item',
templateUrl: './item.component.html',
styleUrls: ['./item.component.css'],
})
export class ItemComponent {
constructor(private backupService: BackupService) {
this.backupService.client.subscribe({
next: (item) => {
if (this.id === item.id) {
this.item = item;
}
},
});
}
@Input() id?: string | null;
protected item?: Item | null;
}
In may app I now have many ItemComponent
instances. By checking the id
inside my observer I avoid an update of all components if only one item
changes.
I would like to improve this by using some kind of Subject
or multicasting design that only shares with observers of some id
. That is, still all components subscribe to one Subject
, but sharing is constrained to only those ItemComponent
s with given id
.
Upvotes: 1
Views: 69
Reputation: 14750
If I'm understanding you correctly, you want subscribers to only receive emissions if the emission is for an item with a specific id
.
In that case, you could modify your subscribe()
method to take in the id and filter out emissions from other items:
public subscribe(id: string, observer?: Partial<Observer<Item>>): Subscription {
return this.subject.pipe(
filter(item => item.id === id)
).subscribe(observer);
}
this.backupService.client.subscribe(this.id, ...);
The above code won't work in the constructor, because the @Input() id
will be undefined until at least the ngOnInit()
lifecycle hook.
The subscribe
method of your BackupClient
class is probably introducing memory leaks. Each time a consumer calls .subscribe()
, you create a subscription, but it doesn't appear that you have a way to ever unsubscribe from them. You may want to consider returning an Observable that consumers subscribe to, then the consumer can be responsible of unsubscribing:
public item(id: string) {
return this.subject.pipe(
filter(item => item.id === id)
);
}
Then in your component:
this.backupService.client.item(this.id).subscribe(...);
Upvotes: 1