Home > other >  Assign new value to property of observable class
Assign new value to property of observable class

Time:06-16

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 });
  • Related