0
votes

I have a button, that is set up to update the parameters of a component. This works when I hit the button, that updates the parameters. Sometimes when I'm refreshing the page or navigating to it trough a URL from an external page, the update logic doesn't work.

I know this is because the behaviorSubject is hard coded to (2019,1,1,'Stores') as shown below. Why the author put that in I'm not sure. All I know is that the object with (2019,1,1,'Stores') is not needed on refresh. I have a method getSLGCurrentWeek() also shown below, that is supposed to update the (2019,1,1,'Stores') to the current year, quarter, and week. Which is now 2020, 1,4.

Why is that hard coded value showing up when I am trying to reset it? Or better yet what would be the best way to get the correct values from the http request getSLGCurrentWeek() so that I can use those values in the getSLGData(params) method?

export class SlgService {

  private slgParamsSource: Subject<SLGReportParams> = new BehaviorSubject<SLGReportParams>(new SLGReportParams(2019, 1, 1, 'Stores'));
  slgParams = this.slgParamsSource.asObservable();

  constructor(private http: HttpClient, @Inject('BASE_URL') private baseUrl: string) { }

  getSLGData(params: SLGReportParams) {
    var slgParams = '?year=' + params.Year + '&quarter=' + params.Quarter + '&week=' + params.Week + '&dept=' + params.Dept;
    return this.http.get(this.baseUrl + 'api/slg/slg' + slgParams);
  }

  getSLGCurrentWeek() {
    return this.http.get(this.baseUrl + 'api/slg/SlgCurrentWeek');
  }

  getSLGWeeks() {
    return this.http.get<any[]>(this.baseUrl + 'api/slg/slgGetAllWeeks');
  }

  updateSLGParams(params: SLGReportParams) {
    this.slgParamsSource.next(params);
  }

}

Here is my ngOnInit()

  ngOnInit() {

    console.log("here")

    this.slgForm = new FormGroup({
      year: new FormControl(),
      quarter: new FormControl(),
      week: new FormControl(),
      dept: new FormControl()
    })

    console.log(this.slgForm)


    //subscribe to slg Service params observable
    this.slgService.slgParams.subscribe(data => {

      this.slgParams = data;
      this.getData(this.slgParams);
    })


    this.slgService.getSLGCurrentWeek().subscribe((data: any) => {
      //set SlgForm with current week values.
      this.slgForm.patchValue({
        year: data.year,
        week: data.week,
        quarter: data.quarter
      })

      this.slgParams = new SLGReportParams(this.slgForm.value.year, this.slgForm.value.quarter, this.slgForm.value.week, this.slgForm.value.dept);
      this.slgService.updateSLGParams(this.slgParams);

      //this.populateSLGTotals();
      //this.operations(data);
      this.getData(this.slgParams)
      //update service with params // Submit has been taken out here
    },
      error => console.log(error),
    )

  }

Button for update

  submit() {
    this.slgParams = new SLGReportParams(this.slgForm.value.year, this.slgForm.value.quarter, this.slgForm.value.week, this.slgForm.value.dept);
    this.slgService.updateSLGParams(this.slgParams);
    console.log("I have submitted")
  }

In conclusion. How to I run this.slgService.getSLGCurrentWeek() to get the params to put into this.slgService.getSLGData(params) without the influence of (2019,1,1,'Stores') from the BehaviorSubject?

Thank you for your assistance.

3
Thank you for all the answers and comments. I am diligently reading through all of these to correct my code. I will notify you when have read through all of these. Thank you and will be back soon. Thanks again! - JSkyS
Thank you for your input. Changed my BehaviorSubject to private slgParamsSource: ReplaySubject<SLGReportParams> = new ReplaySubject<SLGReportParams>(null); And now its not getting reset. I tried to do the same with BehaviorSubject with null value but did not work. Do you have any knowledge why this worked? I am reading a lot on the difference between replaySubject and behaviorSubject but its strange that something that returns multiple calls back would fix the issue. Im confused why it works now. I asked the others below this too. Anyone shed light on this mystery? - JSkyS
Also is there any reason why ReplaySubject<SLGReportParams> = new ReplaySubject<SLGReportParams>(null) would work in debug mode and not production? I just got an error after publishing and had to revert back. - JSkyS

3 Answers

1
votes

Why is that hard coded value showing up when I am trying to reset it?

This happens because you are using BehaviorSubject. That initial value that you provide to the constructor is what you initially get when you do

this.slgService.slgParams.subscribe(data => {
 this.slgParams = data;
 this.getData(this.slgParams);
})

What's interesting about this kind of subject is that it will cache the last emitted value. As a result, new subscribers will receive that value.

Here's how I think you can skip that first emitted value, by using the skip operator.

this.slgService.slgParams
 .pipe(skip(1))
 .subscribe(data => {
   this.slgParams = data;
   this.getData(this.slgParams);
})
1
votes

those are very interesting pieces of code. If I were in your shoes, I would try to do something like the following snippet. If you can reproduce the issue in stackblitz or enter link description here, I can provide you with full example.

ngOnInit() {
  this.slgForm = new FormGroup({
    year: new FormControl(),
    quarter: new FormControl(),
    week: new FormControl(),
    dept: new FormControl()
  })

  this.slgService.getSLGCurrentWeek().pipe(
    map(data => {
      this.slgForm.patchValue({
        year: data.year,
        week: data.week,
        quarter: data.quarter
      })
      // Those are your slg params, that you will get as value from the stream
      return new SLGReportParams(data.year, data.quarter, data.week, this.slgForm.value.dept)
    }),
    switchMap(slgParams => {
      // This will return new stream, with the response of the get data http request
      return this.slgService.getSLGData(slgParams);
    })
  ).subscribe(resp => {
    // Here you will have access to the data recieved from the getData function
    console.log(resp)
  })
}

So what I did differently, Instead of depending on the BehaviorSubject inside of the service, I used a more functional/reactive approach, where I'm getting all the required data with the help of one single subscription, trying to remove all dependencies on data that is external to the request stream.

You can see what I mean, by looking at the way that I'm gathering the slgParams data, instead of depending on the form with the patched values, I'm directly getting the data from the "source" (the data object received in the stream).

A piece of friendly advice, If you are going to work on this project for a longer period of time, I will strongly recommend you invest some time in learning the principals of reactive programming, Angular, rxjs, ngrx.

1
votes

If I may suggest a little track for your problem here => You should be really careful about your subscriptions: Do not forget to "unsubscribe" all of them by implementing ngDestroy. Everytime you'll load your component, it will subscribe again and again.

If you wanna have an idea: Go to your console, and check memory used, or at least check logs, you should see it going to the roof after a while.

I hope this helped you a bit.