The hidden gotcha with async in Angular forms

My modern Angular course: angularstart.com/
In this video, we talk about some of the gotchas and pitfalls to using OnPush Change Detection and Reactive Forms in Angular. This includes dealing with an async validator and changing the status of forms as the result of an asynchronous operation.
Get weekly content and tips exclusive to my newsletter: mobirony.ck.page/4a331b9076
Learn Angular with Ionic: ionicstart.com
Source code: github.com/joshuamorony/angul...
- Previous OnPush Change Detection video: • Why use OnPush in Angu...
- Should we really NEVER subscribe in Angular apps?: • Should we really NEVER...
0:00 Introduction
0:41 Recap of OnPush CD
1:33 Async Validator Example
3:19 Solving with the async pipe
4:34 Other problems with async
6:15 Using ChangeDetectorRef
7:17 The trick
10:03 Conclusion
#rxjs #angular
- More tutorials: eliteionic.com
- Follow me on Twitter: / joshuamorony

Пікірлер: 53

  • @JoshuaMorony
    @JoshuaMorony Жыл бұрын

    Join my mailing list for more exclusive content and access to the archive of my private tips of the week: mobirony.ck.page/4a331b9076

  • @FredDukker
    @FredDukker Жыл бұрын

    Personal I prefer the markForCheck solution. As you said it does the same thing that the async pipe does, so why not do it in the component when async pipe is not a direct solution. I personal don't like the solution of updateValueAndValidity and the async pipe on statusChanges. It is a workaround (two indirect steps) to get angular change detection running. If you need the change detection running, just do it explicitly then everyone understands what is going on.

  • @supsoulja

    @supsoulja

    Жыл бұрын

    lets just app.tick and call it a day

  • @JoshuaMorony

    @JoshuaMorony

    Жыл бұрын

    I think this is a very fair point, and mostly why I put up all the warning tape and mentioned that markForCheck is probably closer to a best practice solution - it's clear and direct. My preference here mostly comes from that I like to use 100% rules wherever possible to be consistent. Ideally for me that means never using CDR to trigger change detection - it forces me to re-architect the application for situations where it isn't really required, and for situations where it technically is the best solution the code might end up being slightly worse. I'm definitely not saying this mentality/philosophy is necessarily correct, it is just my preference. If I have something that works 95% of the time, and I can enforce it 100% of the time with only a slight penalty, I will go with the 100% of the time approach.

  • @Netrole

    @Netrole

    Жыл бұрын

    I always though the point of onPush change detection is that you want to have manual control over change detection and use markForCheck

  • @Elyrinnnn

    @Elyrinnnn

    8 ай бұрын

    100% agree. Stick to the official way or deal with rightfully angry colleagues. That workaround would not get accepted in a pull request.

  • @sergiustanciu8123
    @sergiustanciu8123 Жыл бұрын

    I am loving this channel more and more. Lots of quality information right here. Thank you for the videos!

  • @marcianszlovak5667
    @marcianszlovak5667 Жыл бұрын

    Thanks for these videos, learning a lot from you even after working as a dev for years. Quality content!

  • @brunoramiresferreira4011
    @brunoramiresferreira4011 Жыл бұрын

    Your channel is very good for us. Thanks for the content, keep making it.

  • @RaikoKazuya
    @RaikoKazuya Жыл бұрын

    Excelent content of this channel! I'm learning a lot! Thanks!

  • @Krilllind
    @Krilllind Жыл бұрын

    I'm not sure I agree with the OnPush statement "It helps you architect your applications better" if you are left with an `` element within your HTML just to trigger change detection. To me, the template should be purely for presentation/user interaction. But just like you, I'm not really a big fan of ChangeDetectorRef as if feels like a "hack" to get something working. I am trying to find more valid use cases for OnPush, but so far in an application with over 1000 components I have yet not run in to any performance issues, but I am interested in seeing how it could help with component architecture!

  • @JoshuaMorony

    @JoshuaMorony

    Жыл бұрын

    Hey if you want you can check out the previous video I mentioned: kzread.info/dash/bejne/poutmtyah9nRps4.html which shows an example of the sort of thing I am talking about where OnPush can help force better architecture

  • @jonhines
    @jonhines Жыл бұрын

    I feel like if you were going to add an empty ng-container that will break things if it is removed we should probably be adding a comment to it so that a co-worker doesn't remove it down the road as part of a cleanup effort, but I basically never see comments in angular templates. Is lack of html comments in angular templates left over from the old angular.js days where comments had meaning or is there a better reason no body comments logic in templates?

  • @JoshuaMorony

    @JoshuaMorony

    Жыл бұрын

    This is probably a good idea - I think one of the biggest issues with this approach right now is that it is not an established pattern, so if you do come across it it's going to be confusing. But if this were to become a popular approach (I don't know if it really *should* or not) then that would get rid of that issue. Good tests can protect against this accidental removal as well, but of course many applications don't have tests

  • @alextiger548
    @alextiger548 Жыл бұрын

    Super stuff. Thanks Man!

  • @_emnljrz
    @_emnljrz Жыл бұрын

    It's a good implementation of an async pipe, but kinda hesitant to implement this on a parent-child with multiple forms inside the child component. Perhaps I will try to play around with it. Great explanation 👍

  • @Solumque
    @Solumque Жыл бұрын

    Great stuff!

  • @Iam_AndersonP
    @Iam_AndersonP Жыл бұрын

    The Last trick was the solución i needed for a validación i'm doing on an aplicativo in my current job 🎉🎉🎉🎉🎉

  • @CodingAbroad
    @CodingAbroad Жыл бұрын

    If I have a formarray and in each row there is a drop down list. Is there any problem using async to populate the list of the drop down bearing in mind there are multiple formarrays rows?

  • @TheSaceone
    @TheSaceone Жыл бұрын

    How could we use this approach if we are using custom elements (e.g. implementing control value accessor)? We shouldn't use formControlName should we?

  • @abdul-rahmanal-hussein3265
    @abdul-rahmanal-hussein3265 Жыл бұрын

    Quick question about the validity of a control while an async validator is doing its work, I noticed that valid is turned into false on the control, while invalid stays false, any idea why that happens ? love your work, keep up the good work :D

  • @masterlup
    @masterlup Жыл бұрын

    I guess my best practice would be to compose a "stream of changes" that should trigger cd. *ngIf="runCd$ | async" When using rxAngular we could "hold" the sub

  • @v.bourdeix

    @v.bourdeix

    Жыл бұрын

    Agreed, the "myForm.statusChanges | async" makes no sense when you stumble upon it in the code. It's a manual change detection in disguise that doesn't tell its name, so any developper could come here and think this is useless and decide to remove it, not realizing it was useful. Creating a runCd$ observable clarifies the intention and will allow to group all events that should trigger change detection in one single subscription.

  • @Elyrinnnn

    @Elyrinnnn

    8 ай бұрын

    your naming makes that "magic trick" clearer/better, yes. But just call markForCheck() if you are inside of imperative code. It's the same function that the AsyncPipe calls. Only use *ngIf="xyz$ | async" when it semantically makes sense. Leaving the "Angular way" and creating "magic" instead, is a recipe to anger your colleagues.

  • @AlainBoudard
    @AlainBoudard Жыл бұрын

    I don't like the markForCheck, but that's just me, as you say, it's a matter of choice and how our components are built. Thanks for the reflexions, this is a real issue !

  • @alextiger548
    @alextiger548 Жыл бұрын

    Joshua, how you make to display the browser window inside VS Code on the right side?

  • @JoshuaMorony

    @JoshuaMorony

    Жыл бұрын

    I'm pretty sure there is actually a way to do this with VS Code, but that's not what I'm doing here - I just have two separate windows up on the screen

  • @ToLazyToThink0
    @ToLazyToThink0 Жыл бұрын

    One caution with updateValueAndValidity, it's not reentrant (issue #21109). We ran into the issue when using the valueChanges of one control to update the validation of another.

  • @sanjayjaudon9593
    @sanjayjaudon9593 Жыл бұрын

    thanks helpful vid

  • @DanielC7150
    @DanielC7150 Жыл бұрын

    I'm curious... Was the inspiration for this video from a Reddit comment made recently? As I pretty much posted this exact problem yesterday 😄 If not, just a huge coincidence but I'm looking forward to trying this out!

  • @JoshuaMorony

    @JoshuaMorony

    Жыл бұрын

    Haha the one about "should every component use OnPush"? No, I have these videos planned/recorded a while in advance, but I did see that thread!

  • @CodingAbroad
    @CodingAbroad Жыл бұрын

    Do you personally use nonNullable in all your forms?

  • @JoshuaMorony

    @JoshuaMorony

    Жыл бұрын

    I do now yes

  • @supsoulja
    @supsoulja Жыл бұрын

    @Joshua Morony, maybe dumb but might be possible to use ngrx or at least a behavior subject to wrap the form as a piece of state, then nexting it whenever you need to run it through async for free cd call

  • @AlainBoudard

    @AlainBoudard

    Жыл бұрын

    Yeah, I would go for something like that, a "local store". Although in this video, there is no real update to bring to this piece of state.

  • @JoshuaMorony

    @JoshuaMorony

    Жыл бұрын

    If I'm picturing this in my head correctly, yeah that could be another approach you could use as well.

  • @supsoulja

    @supsoulja

    Жыл бұрын

    @@JoshuaMorony i feel like a validated form right now

  • @loko1944

    @loko1944

    Жыл бұрын

    Even ngrx says we should not put form state there

  • @ShaharHarshuv
    @ShaharHarshuv Жыл бұрын

    Chance goes to show that CD is not the best thing. I'm really psyched about signals. It seems better than change detection or top-down rerendering like in react

  • @yuriblanc8446
    @yuriblanc8446 Жыл бұрын

    i'd use Cdr and you can implement a directive for that that just subscribe to status change and trigger markForCheck

  • @aqbgaming7656
    @aqbgaming7656 Жыл бұрын

    i wanted to watch it later but the thumbnail made me click on it in my office. :{)

  • @Petoj87
    @Petoj87 Жыл бұрын

    I haven't used onPush yet but it seems more like a headache than a blessing..

  • @JoshuaMorony

    @JoshuaMorony

    Жыл бұрын

    I would say it is a headache and then a blessing

  • @peacefultorture
    @peacefultorture Жыл бұрын

    That's a neat trick but I think you just built a case for not using OnPush on every single component. If I was another developer walking into that code, I'd be deleting that seemingly useless ng-container and then wondering why the code is broken. I agree using the CD ref feels like cheating or like you don't actually want OnPush.

  • @michaelglauser7877

    @michaelglauser7877

    Жыл бұрын

    Put a comment in the container as to why it exists.

  • @tntg5
    @tntg5 Жыл бұрын

    'sdfsdf' is also what I end up typing when I need to randomly fill an input 😅

  • @Matrium0
    @Matrium0 Жыл бұрын

    I use OnPush in almost almost all of my dumb components but I'd draw a hard line when I'd have to do some crazy workarounds. The empty ng-container is just bad in my opinion. You'd have to leave a big comment explaining while this is even needed, otherwise there is a good change someone else passing over the component later might think "wait a second, that's not rendering something, let's remove this". And for good reasons, it's a bit of weird hack, isn't it? I think of OnPush similar to you, it's just good practice anyway and creates nice decoupled components. But let's not forget that besides that it is basically a useless performance optimization in like 99,9% of use cases. If you are not reacting to some high-volume events like mouse-moves Angular is blazing fast anyway. For me there is nothing wrong to leave the changedetection as is in those cases - it certainly feels better than the workarounds to me.

  • @michaelcorleone1832
    @michaelcorleone1832 Жыл бұрын

    Long but readable code is way better than too CLEVER short code that is hard to read and understand. Please stick with KISS because you will not maintain the web application in the future.

  • @jhadesdev9576
    @jhadesdev9576 Жыл бұрын

    OnPush is just not practical to use, too many gotchas; you have to an Angular expert to make it work, even for simple use cases. Introducing ImmutableJs is too cumbersome, and NgRx brings a huge development overhead as well. Building a simple form shouldn't be that hard, the framework should make it trivial. My take on it is, unless you really need the performance, which in 99% of the cases you don't, stay away from it it's not worth it.

  • @MyPhone-jf6uf
    @MyPhone-jf6uf6 ай бұрын

    Very bad approach. You started the video without providing context or describing your code 👎

  • @GdeVseSvobodnyeNiki
    @GdeVseSvobodnyeNiki8 ай бұрын

    Async validators are cursed. I have a stepper component where each step contains form. So i need to validate the form when i press "next". And there's no good way to do it. 1) UpdateValueAndValidity returns void, so i can't pipe into the process. 2) Calling updateValueAndValidity does not immediately set form status into pending state, so in my scenario form is still in "valid" state because it was not yet validated => i can't say for sure if the process started or not So i need to do a hack, first calling updateValueAndValidity, then subscribing to a statusChange filtering "PENDING" status and taking exactly 1 value. Could've been replaced with just updateValueAndValidity returning Observable/Promise.

  • @IagoCCampos
    @IagoCCampos Жыл бұрын

    Is there a way that I can get rid off the subscription when I submit the form? (Eg.: this.clientService.addClient(this.form.value).subscribe(() => ...)) Great content btw