I got a problem when updating observable values. I want to create a filter using this class:
export class TrackParams {
sortBy: string = "";
genreId?: number = null;
minPrice = 0;
maxPrice = 999.9;
keyId?: number = null;
minBpm = 0;
maxBpm = 250;
search?: string;
isDraft: boolean = false;
public constructor(init?:Partial<TrackParams>) {
Object.assign(this, init);
}
}
TrackParams
takes any param and assigns it to only 1 created object. So I created service to work with only 1 object with params for filtering.
export class TrackParamsService {
trackParamsSource = new BehaviorSubject<TrackParams>(new TrackParams);
trackParams = this.trackParamsSource.asObservable();
constructor() { }
getTrackParams() {
return this.trackParams;
}
setTrackParams(value: TrackParams) {
this.trackParamsSource.next(value);
}
}
The problem is that I have multiple independent components for changing property value of trackParams
and I can only create a new object of TrackParams
and override other properties with default value.
For example to change genreId
, I have a component with Genres in a dropdown menu and on click that works with TrackParams genreId
:
constructor(private trackParams: TrackParamsService, private trackService: TrackService) { }
onClick(checked, genreId) {
if (checked) {
// Failed attemp
// this.trackParams.trackParamsSource.pipe(
// map(tp => {
// tp.genreId = id}
// )
// ).subscribe((tp) => {});
this.trackParams.getTrackParams().subscribe(tp => {
tp.genreId = id;
});
}
}
I don't want to create a new TrackParams
because it messes up my trackService
where I display the tracks using TrackParam
property values to filter. What's the proper way of doing it?
CodePudding user response:
you could have your service accept an update call with a partial of the filter:
export class TrackParamsService {
trackParams$ = new BehaviorSubject<TrackParams>(new TrackParams);
constructor() { }
updateParams(newFilter: Partial<TrackParams>) {
this.trackParams$.pipe(take(1).subscribe(currentVal => {
this.trackParams$.next({...currentVal, ...newFilter})
});
}
}
then from your components you subscribe to the trackParams$ (no need to call asObservable()
):
this.trackParamsService.trackParams$.subscribe(filter =>{
// do something with the updated filter
}}
(don't forget to avoid the memory-leak trap with subscriptions)
To update the filter from any component, you call the service with your partial attributes:
onClick(checked, genreId) {
if (!checked) return;
this.trackParamsService.updateParams({ genreId }}
}
CodePudding user response:
If I understood correctly, you want to update the property of TrackParams
stored in your BehaviorSubject
. Well, you can't update a single property. You need to provide the entire object, like this:
const tp = this.trackParams.trackParamsSource.value;
this.trackParams.trackParamsSource.next({ ...tp, genreId: id });