Api service with changing arguments using Observables in Angular6
Api service with changing arguments using Observables in Angular6
The behaviour I want: when a user selects a Label from dropdown menu, api is called with that Label as an argument and a chart is redrawn using data received from api. There are multiple identical charts in the page with their respective drop down lists.
The problem is that my solution is not working and I'm not sure how to make it work. My solution:
export class ChartComponent implements OnInit, OnDestroy
private _label = new ReplaySubject<string>()
//Gets value from dropdown menu
@Input() set label(value: string) this._label.next(value)
apiSub: Subscription
constructor(private apiService: ApiService)
ngOnInit()
this.apiSub = this.apiService
.getData(this._label)
.subscribe(this.redrawGraph.bind(this),
console.error
)
ngOnDestroy()
this.apiSub.unsubscribe();
redrawGraph(data:Data)
//Chart drawing logic
export class ApiService {
response= new ReplaySubject<Observable<Data>>()
constructor(private http: HttpClient)
private static _handleError(err: HttpErrorResponse | any) 'Error: Unable to connect to API.');
getData( label: Observable<string> ): Observable<Data>
label.subscribe(label =>
this.response.next(this.http
.get<Data>(`$Urls.DATA?label=$label`)
.catch(ApiService._handleError));
)
return this.response.mergeMap(x => x)
Now redrawGraph() is only called the first time label changes. And there's obviously bad behaviour when several graphs are present, because service is a singleton as far as I know, but I don't know how else to return response without binding it to "this".
What I'm trying to avoid is having to subscribe/unsubscribe to api method from Chart component every time label changes and instead just have one stream: label changes -> api call -> chart redrawn. So how to do it properly?
@FanCheung Are you saying, that it's bad that I'm creating ReplaySubject from input variable?
– Emilijus
Aug 21 at 9:52
1 Answer
1
To make it work you need create individual subject for each chart.
The code will looks like this:
getData( label: Observable<string> ): Observable<Data>
let response : Subject = Subject<Data>();
label.subscribe(label =>
response.next(this.http
.get<Data>(`$Urls.DATA?label=$label`)
.catch(ApiService._handleError));
)
return response;
But this.response refers to class field, so response defined here doesn't get used
– Emilijus
Aug 21 at 9:49
In my example the response is created in getData function. As I uindestood you need several responses for several charst. With one instance of response it will not work for several instances.
– alexey28
Aug 21 at 16:04
I mean "let response" and later "this.response" are two different variables (because of scope), so "return response" just returns that empty "Subject<Data>()
– Emilijus
Aug 23 at 7:49
Agree, I have fix the issue
– alexey28
Aug 23 at 8:19
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
the initial action should be trigger by select option even. Your code is not structured correctly. selectEvent -> pick up label -> pass to api call
– Fan Cheung
Aug 21 at 9:32