Reputation: 443
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.
Upvotes: 0
Views: 1425
Reputation: 1877
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.
Upvotes: 1
Reputation: 3588
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
.
Upvotes: 1
Reputation: 11934
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);
})
Upvotes: 1