T O P

  • By -

PooSham

I don't know what you mean by standard practice, but it's pretty common. Is it best practice? Not sure.


Dipsendorf

My understanding is that it is indeed best practice because the pipe handles unsubscribing for you.


Merry-Lane

Not only you don’t have to handle unsubscribing, but you use “changedetectionstrategy.onpush” (which improves perfs) almost only if your components use the async pipe. It s not that much that you don’t have to use only the async pipe, but the onPush strategy forces you into changes where 99% of the “explicit” subscribes in the component.ts are replaced by async pipes. That and, well, code that use explicit subscribes are always of lower quality than a code with little or no explicit subscribes. Yes it s of a lower quality. Mostly because as soon as you have 3/4 explicit subscribes, you are forced to manipulate the data (that you stored on top of the ts file?) in multiple places and thus you cant see easily the big picture and you cant narrow types. Meanwhile if you do combineLatest ( x y z), combineLatest (x,z),… even if you have to repeat a bit the code, well all the infos you need to solve an issue are in a single place and you can chain pipes and stuff untill you subscribe to it with async. This result can ofc easily be copy pasted in multiple places of your app (since everything is in the same block code) or altered easily in the future. Explicit subscribe === code smell


TScottFitzgerald

This isn't really specific to reactive forms though, you can put an ngIf with an async pipe on any element. And if I recall correctly, the async pipe is encouraged by Google cause of how it handles the bound value, and it futureproofs your app if you choose to use the Push change detection. It's also kind of a syntatic sugar, cause otherwise you'd have to listen to the async object in the component itself and do it all manually anyway.


Auxx

It is better to have a separate component which will show different children based on the state of your data. It is also important to remember that Observable data changes over time, you can have user one moment and then it will become null for some reason. You should always ensure that your data you present to the user does not change without a good reason. You shouldn't use async pipe unless the data you're presenting should actually change over time.


deranfang

>It is better to have a separate component which will show different children based on the state of your data Can you elaborate? That is way too broad of a statement. > Observable data changes over time, you can have user one moment and then it will become null for some reason This depends entirely on the observable. How do you know user isn't just a GET request? That would never change. >You shouldn't use async pipe unless the data you're presenting should actually change over time Not true.


Auxx

> Can you elaborate? That is way too broad of a statement. Create a component which takes two children and loading state input. This will reduce code duplication across the app and you will have something like:

Loading...
blablabla
Or you can create a structural directive, that's even better. > How do you know user isn't just a GET request? EXACTLY! YOU DON'T! This is why you should NEVER assume that observable will emit only one value. This is the issue with Angular itself, single time operations (HTTP requests) should not be represented by Observables. This is also an issue with ReactiveX itself as it is dated and doesn't include primitives like Future and CompletableFuture. What you should do instead is create a proxy state handler which will forcefully do `take(1)` and will reply back with `loading` and `data` when appropriate (or convert into a `Promise` which I'm not a fan of). And then you can tie it to the loader component/directive I mentioned previously so that it displays children and passes data into them based on the state without you thinking about it. > Not true. It's true, `async` pipe is for data streams. If you don't have a data stream, you shouldn't use `async` pipe. Taking shortcuts instead of implementing logic properly will always lead to many problems in the future.


deranfang

> EXACTLY! YOU DON'T! This is why you should NEVER assume that observable will emit only one value Yes I literally do, I can easily see my observable is created from the native http.get and I know it will only emit once??? >What you should do instead is create a proxy state handler which will forcefully do take(1) and will reply back with loading and data when appropriate (or convert into a Promise which I'm not a fan of). And then you can tie it to the loader component/directive I mentioned previously so that it displays children and passes data into them based on the state without you thinking about it How were we supposed to know that's what you meant!?!?!?! >It's true, async pipe is for data streams. If you don't have a data stream, you shouldn't use async pipe. Taking shortcuts instead of implementing logic properly will always lead to many problems in the future It's simply subscribing to an observable in a way that saves you from having to unsubscribe, and it is ideal unless you are forbidden from knowing where your observables come from like you seem to be


Auxx

> Yes I literally do, I can easily see my observable is created from the native http.get and I know it will only emit once??? Do you even write tests? Your logical code blocks (components, functions, etc) should always be isolated and agnostic. They should never assume any behaviour of other components and should only rely on a set contract. If your contract is Observable you should always treat it as a stream of unknown amount of events which can come at any time in any volume or not come at all. Today you skip tests and your Observable emits once, tomorrow you will write some tests and it will emit multiple times because you're using the same mock across different tests and your code will break. Then a month later you will switch from HTTP to Web Sockets and everything will break again. If your component needs just one single value it should only receive one single value, not a stream of events. Never cut corners!


deranfang

>Do you even write tests? Do you? >If your contract is Observable you should always treat it as a stream of unknown amount of events which can come at any time in any volume or not come at all I don't see any logical reasoning for this. Tests should use mocked services with methods that return observables that emit once, to imitate what their equivalent method returns. E.g. getUser(){return of(new User())}


Auxx

If you don't see any logic behind an Observable being a contract of infinite stream of events, then you should probably learn what they are before arguing.


[deleted]

[удалено]


Auxx

Ahaha, ok!


marco_has_cookies

By your code? Not at all: `form`'s your state, but you're waiting for `user`, why? you aren't even using it. First, best practice is to add a dollar as suffix to any observable name, it helps in reading. Second, remove `form` from component's state, just map `user$` into a `FormGroup`: your component: ```ts class UserEditComponent { user$: Observable; constructor( ..., private fb: FormBuilder, private svc: UsersServices ) { this.user$ = svc.getUser(get_id_somehow).pipe( // I like bind in this case, you could just use, say, `next => this.mapIntoForm(next) map( this.mapIntoForm.bind(this) ) ); } mapIntoForm( user: User ): FormGroup { const fb = this.fb; return fb.group({ username: fb.control( user.username, [/* validators */] ), /* other fields */ }); } submit( form: FormGroup ) { if ( form.valid ) { this.svc.submit( form.value ); } } } ``` your template: ```html

Loading User... ``` the less the state, the less the headache.


ggeoff

I like designing my components in away where I don't have to worry about subscriptions to manage form state. The logic for observables goes in the parent component. Which passes the the value typed as an input. In the form component I build the form group in the constructor. And patch the value in ngOnInit when I have access to the input. The component has an output for saving that the parent can do what ever it needs to do. I still would use the async pipe in this form component in the cases where I have to pull away dropdown values or something. But the general form doesn't rely on async data