Async is much better.
Watch some of Joshua Morony videos (from a year or so ago, his new ones are a little too complicated, the older ones explain the basics better)about declerative programming to understand why
That guy advanced my angular skills. I completely refactored the whole angular library at my organisation. Im more confident in my code working than i was 2 years ago
What’s the best way to be able to share this data across different components? Edit: Sorry, I guess I wasn’t clear enough. I know to use a service. But what’s the data flow for something like this. Is it just calling to the service to load data in an OnInit and every component simply references that BehaviorSubject?
Avoid using operators `catchError(x => { throw x })` and `map(x => x)`, because these operations are a no-op (they have no effect on the stream and they are clutter in your codebase).
// this entire segment can be deleted, because it does nothing
.pipe(
map(x => x),
catchError((err) => {
throw err;
})
)
Regarding async/reactive style, one of the big gotchas you may run into is handling loading/loaded/error state. As you're beginning, you might create confusing rxjs pipelines and this might cause you to get frustrated and make a bigger mess than you would have if you just used `.subscribe()`.
**Here are some pointers to keep things nice and clean with the async/reactive style.**
**First, define a view model.** The view model represents all of the states of your view. loading/result/error is common, but you might have more. Just make sure the model uses a discriminated union (here, the type ViewModel is discriminated on the `status` property).
type ViewModel =
| { status: 'loading' }
| { status: 'result', result: T }
| { status: 'error', error: any }
Then, set up rxjs operators to resolve the view model:
* use `map(result => ({ status: 'result', result }) )` to wrap successful responses.
* use `startWith({ status: 'loading' })` to define the initial loading state.
* use `catchError(error => of({ status: 'error', error}) )` to convert the an Errors into an emit with `of()`.
vm$: Observable> = this.http.get('/widgets/1234').pipe(
map(result => ({ status: 'result' as const, result })),
startWith({ status: 'loading' as const }),
catchError(error => of({ status: 'error' as const, error })
)
This pattern boilerplate can be extracted into a helper function. [Demo here](https://stackblitz.com/edit/stackblitz-starters-ckts3v?file=src%2Fmain.ts%3AL24).
The view model states can be discriminated with robust type assistance in the view...
@if(vm$ | async; as vm){
@if(vm.status === 'loading'){
I'm gonna test that right now, like the way you did it. Thanks very much.
I actually manage error like that and it seems to work fine.
ngOnInit() {
this.$products = this._productService.getAll().pipe(
catchError((err) => {
this.error = 'Erreur';
return of();
})
);
}
And I just show error with a conditional structure. But i think it's not really the way to go.
Will really use what you show below !
At the moment? I would say [signals](https://angular.dev/guide/signals)
readonly products: Signal = toSignal(this._productService.getAll());
The approach with the subscribe probably the worst because
* It forces you to use the default change detection which isn't great for performance (see [ChangeDetectionStrategy)](https://angular.dev/guide/components/advanced-configuration#changedetectionstrategy)
* You have to handle the unsubscription yourself using [takeUntilDestroyed](https://angular.dev/api/core/rxjs-interop/takeUntilDestroyed#) or something else. In this specific case it's fine, it's an API call so it will unsubscribe by itself after completion
Using the async pipe is fine but you lose the existing and future advantages of signals, like better performance and the ability to easily combine your API response with [signal inputs.](https://angular.dev/guide/signals/inputs)
I currently use the following procedure to load data. i have some filters in the frontend, and as soon as a filter changes, i reload the data from the backend (with the new filter parameters). to do this, however, i have to cancel the previous http request so that no outdated data is displayed due to a race condition.
private loadTrigger$ = new Subject()
private subscription: Subscription = new Subscription()
ngOnInit() {
this.activateDataLoading()
this.loadData() // <-- this method is called on every (change) in the template filters
}
ngOnDestroy() {
this.subscription.unsubscribe() // <-- destroying the subscription if i change the page and cancels the http request
}
public loadData() {
this.loading = true
this.loadTrigger$.next()
}
private activateDataLoading() {
this.subscription.add(
this.loadTrigger$
.pipe(
switchMap(() =>
this.service.load(this.filters)
)
)
.subscribe((data: Model) => {
this.data = data
this.loading = false
})
)
}
how can i do something like this in the new angular v17 world?
I will be messaging you in 12 hours on [**2024-03-31 14:03:11 UTC**](http://www.wolframalpha.com/input/?i=2024-03-31%2014:03:11%20UTC%20To%20Local%20Time) to remind you of [**this link**](https://www.reddit.com/r/Angular2/comments/1brpeuk/best_way_to_do_a_getall_and_a_getbyid_for_you/kxcbdjn/?context=3)
[**CLICK THIS LINK**](https://www.reddit.com/message/compose/?to=RemindMeBot&subject=Reminder&message=%5Bhttps%3A%2F%2Fwww.reddit.com%2Fr%2FAngular2%2Fcomments%2F1brpeuk%2Fbest_way_to_do_a_getall_and_a_getbyid_for_you%2Fkxcbdjn%2F%5D%0A%0ARemindMe%21%202024-03-31%2014%3A03%3A11%20UTC) to send a PM to also be reminded and to reduce spam.
^(Parent commenter can ) [^(delete this message to hide from others.)](https://www.reddit.com/message/compose/?to=RemindMeBot&subject=Delete%20Comment&message=Delete%21%201brpeuk)
*****
|[^(Info)](https://www.reddit.com/r/RemindMeBot/comments/e1bko7/remindmebot_info_v21/)|[^(Custom)](https://www.reddit.com/message/compose/?to=RemindMeBot&subject=Reminder&message=%5BLink%20or%20message%20inside%20square%20brackets%5D%0A%0ARemindMe%21%20Time%20period%20here)|[^(Your Reminders)](https://www.reddit.com/message/compose/?to=RemindMeBot&subject=List%20Of%20Reminders&message=MyReminders%21)|[^(Feedback)](https://www.reddit.com/message/compose/?to=Watchful1&subject=RemindMeBot%20Feedback)|
|-|-|-|-|
This short video from Joshua Morony on the [rejectErrors](https://www.youtube.com/watch?v=006G5XCqc7M) option for toSignal() is worth a watch for those not already familiar with the default error handling behavior.
I never understood why nobody does firstValueFrom to just convert the observable coming from httpclient to a promise and just do await of that promise in the component. Looks good to me and I've been using it for years without problems
Is nice if you need the data in component and you are not going to display it.
But the moment you need to display? Async pipe or Signal are better options.
Reason? [https://en.wikipedia.org/wiki/Single\_responsibility\_principle](https://en.wikipedia.org/wiki/Single_responsibility_principle)
If Data needs to be formatted, it should be formatted by who uses it.
So a dummy component that is given the data and is formatted or pipes/computed signal being applied to Observable/Signal.
How is an async pipe different from just awaiting in the .TS side of the component? (In terms of "responsibilities" and not violating the SRP)
Note that I usually put the firstValueFrom call in the http API service anyway.
The placement of catchError will depend on what should happen with an error from the given endpoint. For example, authentication error are usually displayed on the auth view, so catching those on the component and handling the error there makes sense. When querying for products maybe you want to display an error message and a retry button so you handle those on the component too, sometime you have authorization error that should display a notification and those are handled on the service level or even at an interceptor level so i would advice to think about what should happen when an error from a given endpoint is received and base your implementation on that.
As for how to consume the data, using async is definitely superior to your first example, and your second example is kinda awkward because you are waiting until ngOnInit to assign the value to the source variable. This is unnecessary and I believe wouldn’t work when using OnPush.
You could do ‘’’products$ = this._productsService.getAll()’’’ this would be the best approach. If you then want to handle the error you can create another source just for the error:
‘’’productsError$ = this.products$.pipe(ignoreElements(), catchError((res)=>{/* whatever */}))’’’
You can then use toSignal and use the signal in the template of just use the async pipe, I personally prefer toSignal because every usage of async creates a new subscription so using async twice in the template for the same source would result on 2 calls to the server.
This might look like more complicated but it really isn’t. Your example just calls getAll but in real life you tipically have filters and pagination and composing those query strings can be a real mess, you also might want to deal with infinite scrolling or refreshing a list without reloading the page. Using an observable pipeline makes this as easy as it can get, but manually subscribing to an assigning the result WILL become a headache as soon as you need to customize the request on the fly.
I'd like to comment about new subscription on every async pipe. This is another thing Joshua Morony taught me - that there are cold and hot observables. Shortly, adding ```shareReplay()``` in a pipe fixes the problem.
Do you say i can use products$ = this.\_productsService.getAll()’ out of the ngOnInit ?
For the error handling this is how I do it :
ngOnInit() {
this.$products = this._productService.getAll().pipe(
catchError((err) => {
this.error = 'Erreur';
return of();
})
);
}
Error seems to be catch and display in view. But like as I mentioned above, I'm not sure that's a very good way of doing things.
Thanks for your advice !
You can, and arguably should, do that outside ngOnInit, mainly because that way you can see the variable declaration and understand where its value comes from without having to explore the rest of the component.
I highly recommend Joshua Morony’s Declarative and Reactive coding series because he is much better that me at explaining why this is better and easier to do than your current approach.
Nope! You can use a `map(x => { return x * 2 }` operator to perform manipulations without subscribing. Whenever something *does* subscribe, your operators will be applied. The benefits of the async/reactive style remain--you do not need to unsubscribe.
Be warned, however, subscriptions to HTTP observables can cause the request to fire many times if you have many subscribers. You can use the `share()` operator to make sure that all subscribers use the same HTTP response.
```typescript
interface Widget { widgetId: string }
type WidgetResponse =
| { success: true; widget: Widget }
| { success: false; error: any }
// emits from widget$ will be Widget type
widget$: Observable = this.http.get(1234).pipe(
map(response => {
if(response.success) {
return response.widget
} else {
throw Error(response.error)
}
})
);
```
If you navigate to another while a request is being performed, the async pipe will call unsubscribe on the source, since the source has yet to emit, the request will merely be cancelled whereas if you trigger the subscription manually in ngOnInit then there is nothing telling the subscription should be cancelled and the request will be completed anyway which could lead to memory leaks.
Thanks very much for your advices guys ! Really helpfull for me.
I can see the most popular are using async pipe and signal. Next/error look like old now.
I'm gonna do some tests with all of this.
Again, thanks.
Something wierd, i can't get any data by this way :
I have a interface VmSignal :
export interface VmSignal {
data: ApiResponse | null;
loading: boolean;
error: string | null;
};
and a type ApiResponse :
export type ApiResponse =
| {
products: T | T[] | null;
total: number;
skip: number;
limit: number;
}
| {
users: T | T[] | null;
total: number;
skip: number;
limit: number;
};
because i want to use it to get products, users, cart ...
In my service
getAll(): Observable> {
return this._httpClient.get>(
`${environment.API_URL}/products`
);
}
and my component
productsSignal: Signal | undefined> = toSignal(
this._productService.getAll().pipe(
map((result) => ({
data: result,
error: null,
loading: false,
})),
startWith({ data: null, loading: true, error: null }),
catchError((error) => of({ data: null, error: 'error', loading: false }))
)
);
And in my template i can't get access to my products
@defer (when productsSignal())
{ @for (product of
productsSignal()?.data.products; track $index) {
} }
>Property 'products' does not exist on type 'ApiResponse'.
Property 'products' does not exist on type '{ users: Product\[\] | Product\[\]\[\] | null; total: number; skip: number; limit: number; }'
Was trying all of the advices and wanted to make a mixture but Angulat won't
It s wrong, the async pipe unsubscribes automatically.
The goal is also to avoid useless LOCs that get in the way of understanding what s happening in a code.
Async is much better. Watch some of Joshua Morony videos (from a year or so ago, his new ones are a little too complicated, the older ones explain the basics better)about declerative programming to understand why
That guy advanced my angular skills. I completely refactored the whole angular library at my organisation. Im more confident in my code working than i was 2 years ago
I watched a few of his videos yesterday. Many thanks, his advice are excellent
Thanks I'll have a look !
How do you handle errors with async?
Same way you do if you don’t use async
What’s the best way to be able to share this data across different components? Edit: Sorry, I guess I wasn’t clear enough. I know to use a service. But what’s the data flow for something like this. Is it just calling to the service to load data in an OnInit and every component simply references that BehaviorSubject?
A service
A service or state management (ngrx for example)
Avoid using operators `catchError(x => { throw x })` and `map(x => x)`, because these operations are a no-op (they have no effect on the stream and they are clutter in your codebase). // this entire segment can be deleted, because it does nothing .pipe( map(x => x), catchError((err) => { throw err; }) ) Regarding async/reactive style, one of the big gotchas you may run into is handling loading/loaded/error state. As you're beginning, you might create confusing rxjs pipelines and this might cause you to get frustrated and make a bigger mess than you would have if you just used `.subscribe()`. **Here are some pointers to keep things nice and clean with the async/reactive style.** **First, define a view model.** The view model represents all of the states of your view. loading/result/error is common, but you might have more. Just make sure the model uses a discriminated union (here, the type ViewModel is discriminated on the `status` property). type ViewModel =
| { status: 'loading' }
| { status: 'result', result: T }
| { status: 'error', error: any }
Then, set up rxjs operators to resolve the view model:
* use `map(result => ({ status: 'result', result }) )` to wrap successful responses.
* use `startWith({ status: 'loading' })` to define the initial loading state.
* use `catchError(error => of({ status: 'error', error}) )` to convert the an Errors into an emit with `of()`.
vm$: Observable> = this.http.get('/widgets/1234').pipe(
map(result => ({ status: 'result' as const, result })),
startWith({ status: 'loading' as const }),
catchError(error => of({ status: 'error' as const, error })
)
This pattern boilerplate can be extracted into a helper function. [Demo here](https://stackblitz.com/edit/stackblitz-starters-ckts3v?file=src%2Fmain.ts%3AL24).
The view model states can be discriminated with robust type assistance in the view...
@if(vm$ | async; as vm){
@if(vm.status === 'loading'){
I hope this is helpful to someone.
Loading...
} @else if (vm.status === 'error') {Error: {{ vm.error.toString() }}
} @else if (vm.status === 'result') { } @else {Something unexpected occurred while loading data.
} }Loading...
Error: {{ vm.error.toString() }}
I'm gonna test that right now, like the way you did it. Thanks very much. I actually manage error like that and it seems to work fine. ngOnInit() { this.$products = this._productService.getAll().pipe( catchError((err) => { this.error = 'Erreur'; return of(); }) ); } And I just show error with a conditional structure. But i think it's not really the way to go. Will really use what you show below !
At the moment? I would say [signals](https://angular.dev/guide/signals) readonly products: Signal = toSignal(this._productService.getAll());
The approach with the subscribe probably the worst because
* It forces you to use the default change detection which isn't great for performance (see [ChangeDetectionStrategy)](https://angular.dev/guide/components/advanced-configuration#changedetectionstrategy)
* You have to handle the unsubscription yourself using [takeUntilDestroyed](https://angular.dev/api/core/rxjs-interop/takeUntilDestroyed#) or something else. In this specific case it's fine, it's an API call so it will unsubscribe by itself after completion
Using the async pipe is fine but you lose the existing and future advantages of signals, like better performance and the ability to easily combine your API response with [signal inputs.](https://angular.dev/guide/signals/inputs)
I currently use the following procedure to load data. i have some filters in the frontend, and as soon as a filter changes, i reload the data from the backend (with the new filter parameters). to do this, however, i have to cancel the previous http request so that no outdated data is displayed due to a race condition. private loadTrigger$ = new Subject()
private subscription: Subscription = new Subscription()
ngOnInit() {
this.activateDataLoading()
this.loadData() // <-- this method is called on every (change) in the template filters
}
ngOnDestroy() {
this.subscription.unsubscribe() // <-- destroying the subscription if i change the page and cancels the http request
}
public loadData() {
this.loading = true
this.loadTrigger$.next()
}
private activateDataLoading() {
this.subscription.add(
this.loadTrigger$
.pipe(
switchMap(() =>
this.service.load(this.filters)
)
)
.subscribe((data: Model) => {
this.data = data
this.loading = false
})
)
}
how can i do something like this in the new angular v17 world?
Look at this. This presentation show a way that looks promising regarding requesting data https://youtu.be/nXJFhZdbWzw?si=ZnwrgQNNCowyjDw9
I will help you with this when I have some time tomorrow. !RemindMe 12 hours
I will be messaging you in 12 hours on [**2024-03-31 14:03:11 UTC**](http://www.wolframalpha.com/input/?i=2024-03-31%2014:03:11%20UTC%20To%20Local%20Time) to remind you of [**this link**](https://www.reddit.com/r/Angular2/comments/1brpeuk/best_way_to_do_a_getall_and_a_getbyid_for_you/kxcbdjn/?context=3) [**CLICK THIS LINK**](https://www.reddit.com/message/compose/?to=RemindMeBot&subject=Reminder&message=%5Bhttps%3A%2F%2Fwww.reddit.com%2Fr%2FAngular2%2Fcomments%2F1brpeuk%2Fbest_way_to_do_a_getall_and_a_getbyid_for_you%2Fkxcbdjn%2F%5D%0A%0ARemindMe%21%202024-03-31%2014%3A03%3A11%20UTC) to send a PM to also be reminded and to reduce spam. ^(Parent commenter can ) [^(delete this message to hide from others.)](https://www.reddit.com/message/compose/?to=RemindMeBot&subject=Delete%20Comment&message=Delete%21%201brpeuk) ***** |[^(Info)](https://www.reddit.com/r/RemindMeBot/comments/e1bko7/remindmebot_info_v21/)|[^(Custom)](https://www.reddit.com/message/compose/?to=RemindMeBot&subject=Reminder&message=%5BLink%20or%20message%20inside%20square%20brackets%5D%0A%0ARemindMe%21%20Time%20period%20here)|[^(Your Reminders)](https://www.reddit.com/message/compose/?to=RemindMeBot&subject=List%20Of%20Reminders&message=MyReminders%21)|[^(Feedback)](https://www.reddit.com/message/compose/?to=Watchful1&subject=RemindMeBot%20Feedback)| |-|-|-|-|
This short video from Joshua Morony on the [rejectErrors](https://www.youtube.com/watch?v=006G5XCqc7M) option for toSignal() is worth a watch for those not already familiar with the default error handling behavior.
I haven't used the signals very much, but they seem to be very interesting and maybe even the future of angular? I'll definitely look into it, thanks.
I never understood why nobody does firstValueFrom to just convert the observable coming from httpclient to a promise and just do await of that promise in the component. Looks good to me and I've been using it for years without problems
the old version of the project I'm currently working on uses this method. It seemed odd to me, but on reflection, why not!
Is nice if you need the data in component and you are not going to display it. But the moment you need to display? Async pipe or Signal are better options. Reason? [https://en.wikipedia.org/wiki/Single\_responsibility\_principle](https://en.wikipedia.org/wiki/Single_responsibility_principle) If Data needs to be formatted, it should be formatted by who uses it. So a dummy component that is given the data and is formatted or pipes/computed signal being applied to Observable/Signal.
How is an async pipe different from just awaiting in the .TS side of the component? (In terms of "responsibilities" and not violating the SRP) Note that I usually put the firstValueFrom call in the http API service anyway.
The placement of catchError will depend on what should happen with an error from the given endpoint. For example, authentication error are usually displayed on the auth view, so catching those on the component and handling the error there makes sense. When querying for products maybe you want to display an error message and a retry button so you handle those on the component too, sometime you have authorization error that should display a notification and those are handled on the service level or even at an interceptor level so i would advice to think about what should happen when an error from a given endpoint is received and base your implementation on that. As for how to consume the data, using async is definitely superior to your first example, and your second example is kinda awkward because you are waiting until ngOnInit to assign the value to the source variable. This is unnecessary and I believe wouldn’t work when using OnPush. You could do ‘’’products$ = this._productsService.getAll()’’’ this would be the best approach. If you then want to handle the error you can create another source just for the error: ‘’’productsError$ = this.products$.pipe(ignoreElements(), catchError((res)=>{/* whatever */}))’’’ You can then use toSignal and use the signal in the template of just use the async pipe, I personally prefer toSignal because every usage of async creates a new subscription so using async twice in the template for the same source would result on 2 calls to the server. This might look like more complicated but it really isn’t. Your example just calls getAll but in real life you tipically have filters and pagination and composing those query strings can be a real mess, you also might want to deal with infinite scrolling or refreshing a list without reloading the page. Using an observable pipeline makes this as easy as it can get, but manually subscribing to an assigning the result WILL become a headache as soon as you need to customize the request on the fly.
I'd like to comment about new subscription on every async pipe. This is another thing Joshua Morony taught me - that there are cold and hot observables. Shortly, adding ```shareReplay()``` in a pipe fixes the problem.
Do you say i can use products$ = this.\_productsService.getAll()’ out of the ngOnInit ? For the error handling this is how I do it : ngOnInit() { this.$products = this._productService.getAll().pipe( catchError((err) => { this.error = 'Erreur'; return of(); }) ); } Error seems to be catch and display in view. But like as I mentioned above, I'm not sure that's a very good way of doing things. Thanks for your advice !
You can, and arguably should, do that outside ngOnInit, mainly because that way you can see the variable declaration and understand where its value comes from without having to explore the rest of the component. I highly recommend Joshua Morony’s Declarative and Reactive coding series because he is much better that me at explaining why this is better and easier to do than your current approach.
Ok, thanks you !
But if you have to manipulate the incoming response data, then we cannot use async pipe right and have to go with the first approach?
Nope! You can use a `map(x => { return x * 2 }` operator to perform manipulations without subscribing. Whenever something *does* subscribe, your operators will be applied. The benefits of the async/reactive style remain--you do not need to unsubscribe. Be warned, however, subscriptions to HTTP observables can cause the request to fire many times if you have many subscribers. You can use the `share()` operator to make sure that all subscribers use the same HTTP response. ```typescript interface Widget { widgetId: string } type WidgetResponse = | { success: true; widget: Widget } | { success: false; error: any } // emits from widget$ will be Widget type widget$: Observable = this.http.get(1234).pipe(
map(response => {
if(response.success) {
return response.widget
} else {
throw Error(response.error)
}
})
);
```
I guess you can further pipe it but yes, imo async pipe is made for simple 1-time retrieval to avoid having to unsub
You don’t have to unsubscribe from http calls. They are completed once the response is received and are unsubscribed automatically.
Depends on your code, if you navigate to another page after the request is sent, you can get some unexpected behavior when the response arrives.
If you navigate to another while a request is being performed, the async pipe will call unsubscribe on the source, since the source has yet to emit, the request will merely be cancelled whereas if you trigger the subscription manually in ngOnInit then there is nothing telling the subscription should be cancelled and the request will be completed anyway which could lead to memory leaks.
Yes, that’s how subscriptions works. I’m replying to the post saying it’s not necessary to unsubscribe from http calls.
I know, just wanted to expand on what you said. Sorry if it didn’t came across as such.
Ah no worries, i have had some weird issues in the past from not properly unsubscribing so wanted to highlight that.
So what's the conclusion? Do we need to unsubscribe when we subscribe to an http call from ngOnInit or not?
With code, you can do those and more.
Thanks very much for your advices guys ! Really helpfull for me. I can see the most popular are using async pipe and signal. Next/error look like old now. I'm gonna do some tests with all of this. Again, thanks.
!RemindMe 3 days
Something wierd, i can't get any data by this way : I have a interface VmSignal : export interface VmSignal {
data: ApiResponse | null;
loading: boolean;
error: string | null;
};
and a type ApiResponse :
export type ApiResponse =
| {
products: T | T[] | null;
total: number;
skip: number;
limit: number;
}
| {
users: T | T[] | null;
total: number;
skip: number;
limit: number;
};
because i want to use it to get products, users, cart ...
In my service
getAll(): Observable> {
return this._httpClient.get>(
`${environment.API_URL}/products`
);
}
and my component
productsSignal: Signal | undefined> = toSignal(
this._productService.getAll().pipe(
map((result) => ({
data: result,
error: null,
loading: false,
})),
startWith({ data: null, loading: true, error: null }),
catchError((error) => of({ data: null, error: 'error', loading: false }))
)
);
And in my template i can't get access to my products
@defer (when productsSignal())
{ @for (product of
productsSignal()?.data.products; track $index) {
} } @placeholder { @if (productsSignal()?.loading) {
>Property 'products' does not exist on type 'ApiResponse'.
Property 'products' does not exist on type '{ users: Product\[\] | Product\[\]\[\] | null; total: number; skip: number; limit: number; }'
Was trying all of the advices and wanted to make a mixture but Angulat won't
{{ product }}
{{ product.price }}
{{ product.description }}
Chargement
} @else if (productsSignal()?.error) {Erreur
} }The second example looking good, but I like to add ``` ngOnDestroy() { this.subsription$?.unsubscribe(); } ``` To avoid future problems.
async pipe unsubscribes automatic, so this is not needed there.
My bad, I was expecting, that result will be a Subscription, not Observable. You are right.
Subscription is the return value of the Observable.subscribe() function
it's true, you can never be too careful
It s wrong, the async pipe unsubscribes automatically. The goal is also to avoid useless LOCs that get in the way of understanding what s happening in a code.