#Avoid subscription in the component
75 messages · Page 1 of 1 (latest)
customActionEvent(event: CustomActionModel) {
let eventValue = event.value as VehicleTaxDeregistration;
if (event.id === GridOptions.viewDetails) {
}
if (event.id === GridOptions.downloadPdf) {
/* Download pdf */
this.vehicleTaxDeregistrationService.readApplicationPdf(eventValue.id!).subscribe((result: any) => {
const a = document.createElement('a');
const objectUrl = URL.createObjectURL(result);
a.href = objectUrl;
a.download = "Cerere";
a.click();
URL.revokeObjectURL(objectUrl);
}
if (event.id === GridOptions.editApplication) {
}
}
like here, when I click on a Grid option I want to download an Pdf file
yes its fine to subscribe in the component
if you want to be safe make sure you unsubscribe when the component is destroyed
subscription
customActionEvent() {
this.subscription = something.subscribe()
}
ngOnDestroy() {
this.subscription?.unsubscribe()
}
Or add some sort of timeout to make sure the observable completes to prevent memory leaks. You only need this if your observable doesn't complete on its own.
As a rule of thumb, it's better to always unsubscribe on destruction.
Ideally, you would set up your observables in such a way that you dont need that subscribe in the first place. But that's not always easy.
That's where I always believed ngrx effects shine.
Yes I try that, but I don't have any Idea how to do that, when I'm not getting data out of observables..
Lets say your data is in an observable called this.data$, you can always get the data from there using all kinds of ways:
const dataFromApi$ = combineLatest([this.data$])
.pipe(
switchMap(([data]) => this.someService.doPostWithData(data))
);
This will automatically trigger the post call when the data changes. Which is not always what u want.
Can add take(1) if u like, or use a specific trigger:
const dataFromApi$ = this.trigger$
.pipe(
withLatestFrom([this.data$]),
switchMap(([data]) => this.someService.doPostWithData(data))
);
Then call this.trigger$.next() when u want to actually call the API.
This will achieve the same, without a single subscription
Which is not that different from ngrx effects would work, it's just all abstracted a bit nicely for u.
Hmm, for switchMap to actually do something is not necessary an subscribe, or you mean to use async pipe in template?
Yeah async sorry.
You will always need subscriptions, but you want to avoid manual subscribing.
One more question, this will not make an POST request, initially when I want to get data out of Observable and display in in the template?
let's say I have a Form, I want to patch all the values for the form
and after the user update the dates, I need to do an POST request
The first version will trigger whenever the data observable changes/emits.
U can use the second example, which u can trigger from anywere.
I know this with trigger$.next()
but initially If I only want to display the data in the template
?
can I do this?
dataFromApi$ | async as dataFromApi ?
I dont know what u mean.
U need to get the data from the api first.
U dont need data for that ?
Yes, that's what I mean, I need to patch the existing Form, and after that when submitting to do the POST request
But the first is a GET call?
yes
So you are talking about something else
this is the post call...
Does the post call return the same data as the get?
in my app yes
Usually my flow is to get data from the backend, modify it in a Form and after that submit the new data to the backend
how I implemented, I do | async pipe for GET request
and after subscribe
for the POST Request
U can use:
const dataFromApi$ = merge([
this.someService.getData(),
this.trigger$
.pipe(
withLatestFrom([this.data$]),
switchMap(([data]) => this.someService.doPostWithData(data))
)
)];
ok so the trigger can contain the form value like a Subject, this.trigger$.next(this.form.getRawValue()) ?
it could if u want sure. That would simplfy things:
const dataFromApi$ = merge([
this.someService.getData(),
this.updateData$
.pipe(
switchMap((data) => this.someService.doPostWithData(data))
)
)];
Renamed it to updateData instead.
yeah that's look cool, thanks
And it also represents what u just said:
dataFromApi will represent initial data, as well as data after every update.
const dataFromApi$ = merge([
this.someService.getData(),
this.updateData$
.pipe(
switchMap((data) => this.someService.doPostWithData(data).pipe(tap(() => redirectToSomething()))
)
)];
this will work too?
redirect to another page, after the POST request
Sure
Ok thanks
One question please, how merge work here?
I know combineLatest emit when every observable emit once
and forkJoin emit when all observables are completed
merge emit from both observables
so if updateData$ didin't emitted yet
it still work?
Yes.
hm ok, so that's the difference.
combineLatest, forkJoin and merge
because first two doesn't work if one of observable does not emit or complete
Yeah thats true.
But this.someService.getData(), and the POST request
need to
return same type of Data right?
Yeah, thats what u want when using merge
if this was not the case, what is the correct operator?
What ? Different data ?
yes
Different data shouldnt be represented in a single observable.
const viewmodel$ = merge([
this.someService.getData(),
this.updateData$
.pipe(
switchMap((data) => this.someService.doPostWithData(data).pipe(tap(() => redirectToSomething()))
)
]).pipe(map(() => map to view model if necessary);
Beware: combineLatest will wrap result in an array with all the sources latest values, while merge will only emit a single value at a time in order of occurrence.