This is the myth I hope the video helps tackle. There is no good reason to use it as default, the complexity cost that comes with it is not a good fit for a lot of teams.
you can adjust angular cli so that newly created components will have onPush by default by running this or appending schematic in angular.json by hand ng config schematics.@schematics/angular.component.changeDetection OnPush
I agree. I watched the video and I feel like I have two problems with it: 1. The complexity really only comes into play when deciding on a "pattern" for your team to follow, which will be handled by the leads/seniors. Once it's in play, be it through immutability, centralized stores, RXJS pipes, or signals, it really won't be hard for anyone, even a junior, to just copy how everything else is done. 2. The performance difference is being downplayed hard. Yes, in many cases you will not need OnPush, because your components will be very dumb. But, not using OnPush allows for poor practices to be used (e.g. binding to a mildly complex function) without consequence. I also think that if you are more relaxed towards it, when a performance problem does come around, you may not be prepared architecturally to effectively debug/refactor it. IMO there are certainly times where using default CD will benefit the code. But, you should still take the mindset of enforcing everything be OnPush by default, and only flip it back if there is solid justification for it. That's especially the case these days, where it's so easy to make a reactive template.
There's yet another way to do `OnPush` using reified reactivity, i.e. using `Observables` and `BehaviorSubject`s instead of mutating references with new objects. This is more complex still but makes managing concurrency easy if you need to (debounce, retry, etc). It doesn't really require zone.js and is much closer to a signal based solution.
Just my opinion based on a couple of enterprise-grade projects I've worked I think this (i.e. using Default change detection) encourages bad application architecture & component hygene. With the default setting, engineers will tend to use components instead of services for state management / manipulation, which could result in hundreds of lines of spaghetti code that handles data fetching, data management & UI interaction (no clean separation of concerns). Mutating state (as in your example) like that in components can be a nightmare to debug / test. (That being said, OnPush with markForCheck() or detectChanges() being called everywhere is even worse, but if that is something engineers try to avoid, I've found "purer" / simpler components are created). There is also the mental model overhead of knowing when to use OnPush vs Default, rather than always following a single pattern. The cleanest approach I've found is having services that handles data updates & provides immutable state via observables, which allows all the components to have less business logic.
You can do bad architecture and bad code with either OnPush and default change detection. You can write clean components and services with default just as well, with the added benefit that it's much more straighforward and easy to use. , it's just a myth that OnPush will help avoid this.
I'm interested to see what you're going to say, Vasco. I ALWAYS use OnPush to keep change detection localised to the component tree segment in question rather than need the full check of the default behaviour.
This does make sense. I think the big difference is that right from the start I built with a centralised immutable store which delivers everything into components using Observables. I've also found using signal inputs since v17.2 a game changer for simplicity of component design. Thanks for this excellent explanation as always, Vasco!
I think the claim that using OnPush requires a vastly different way of coding components vastly overstates the changes needed. I've changed default generator to add OnPush with almost no changes ever needed. The big difference I see between my code and @AngularUniversity is that AU is using plain old container objects instead of Observables. In my experience almost all data such as Course[] is supplied from an asynchronous provider, e.g. advancedCourses$: Observable. In the example code, I think a separate component would solve the problem. Alternatively, I think injecting the ChangeDetectorRef and marking for update would work. Have not tested either
Thank you for commenting, but that is actually maybe the main difference. OnPush makes it hard to use just plain member variables, which is a very natural programming model. OnPush forces you to either feed the data via Observables, create separate components just to have an input for things that would otherwise not be a separate component, or use ChangeDetectorRef everywhere. This is all doable, but significantly more complex than what default change detection gives you, just plain member variables without the need for Observables. 👍
@@AngularUniversity But the problem is that dynamic plain old containers just don't appear on any reasonably sized app, i.e. any app that makes API calls. If it's not making any API calls it's very likely static and change detection does not matter. The actual angular-course page makes a request to get the courses. Does it not use async? The lessonsService? If you managed that without observables, that's a lesson I'd love to learn!
@@NuncNuncNuncNunc Yes correct you don't need Obervables or the async pipe. With default change detection, you can just have a plain member variable and access it from the template.
@@AngularUniversity I think you've completely missed my point. I'll be direct - plain old javascript containers are not used for dynamic content. Since they are not used, there is no added complexity of using observables. They are already baked in. The consequence is that there is no mental overhead nor additional code overhead to always using OnPush. Do your services on the Angular University return plain objects? If so, please, please, please make a lesson on how to that and include features like isLoading, onSuccess, onFailure, etc.
@@NuncNuncNuncNunc and just to be clear, what do you mean by Javascript containers, you mean primitive Objects and Arrays, or something else? usually my services return Promises, you can get the primitive value with async / await then assign it to a member variable.Your component data does not have to be Observables in Angular, it can be just plain data, objects and arrays as member variables. It works beautifully, very simple and intuitive. 👍 But that programming model is essentially not doable in OnPush in a practical way.
Hello, first of all, thank you for making all these amazing angular guide/best practice videos. I'm planning to refactor most part of our project code to be signal based. I'm wondering if It would be more advantageous to use onPush change detection on signal based pages/components? Thanks and more power!
If you refactor the code into signals, it will work with both OnPush and default change detection, although signals are not plugged yet into default change detection. OnPush is already integrated with signals, if you consume a signal in an OnPush template it will mark the component as dirty, just like with the async pipe. I'm personally still waiting to see what signal-based change detection will look like, before starting to refactor into signals. 👍
I heard an opinion that onPush should be used most of the time to force good architecture on developer, that is to use async pipes and split components to dumb and smart so the data is passed through inputs etc and I think it is quite good point Modifying objects and arrays in this case can be tricky indeed but I find myself not doing that most of the time as after some update on page data needs to be refreshed with DB anyways so then streams come into play and async pipes So I think modifying objects and arrays inside inputs could be called edge cases Interesting video anyways, I'm curious how would you respond to that 😊
it's a myth that the constraints that OnPush brings with it are somehow beneficial. Those constraints are inconvenient for the developer and come at a price. Most of the times, that complexity price is not worth paying. 👍 I think we should use the right tool for the job and not making things unnecessarily complex without any added benefit.
Thank you for a great video, as usual. I have a data table with over 100 columns and over 300 rows. The table data is partially updated multiple times per second, through a websocket connection and the speed of the app is of paramount importance. Is onPush making a difference here or not? Tried with both strategies and I do not notice a performance difference. So it is more on how performant is a material data table, rather than the Angular's change detection merit on final user experience !?
I think that this is a great example, that even with a fair amount of data, default change detection is not an issue; Usually what is harming performance in situations with large tables with a large number of DOM elements is the number of DOM elements itself, and not the change detection. I recommend trying Angular CDK virtual scrolling, it works just like ngFor - th-cam.com/video/CemKQarA2xM/w-d-xo.html 😊
@@AngularUniversity I didn't even know it existed to be honest!! My issue now with angular is how more complex it's getting more like Java than the true front end! Patterns and now new things!!
@@AngularUniversity I have a change detection error because angular sees the component as null but then when I reveal the actual component on the dom it finds it and complains, the issue is I'm passing the reference to that component by input binding and I can't find the solution
If you are looking to learn Angular, check out the courses from Beginner to Advanced at the Angular University - angular-university.io/
On push has made my change detection substantially more predictable and less buggy. I’ve rewritten all projects to use on push.
Personally I think OnPush should be used everywhere. I would use it as a default if it was possible.
This is the myth I hope the video helps tackle. There is no good reason to use it as default, the complexity cost that comes with it is not a good fit for a lot of teams.
@@AngularUniversity To be honest, I haven't watched the video yet. I'll check it later, perhaps my view will change.
@@bartekaszczuk5201 Awesome, I'm curious to hear your thoughts once you have watched it 😊
you can adjust angular cli so that newly created components will have onPush by default by running this or appending schematic in angular.json by hand
ng config schematics.@schematics/angular.component.changeDetection OnPush
I agree. I watched the video and I feel like I have two problems with it:
1. The complexity really only comes into play when deciding on a "pattern" for your team to follow, which will be handled by the leads/seniors. Once it's in play, be it through immutability, centralized stores, RXJS pipes, or signals, it really won't be hard for anyone, even a junior, to just copy how everything else is done.
2. The performance difference is being downplayed hard. Yes, in many cases you will not need OnPush, because your components will be very dumb. But, not using OnPush allows for poor practices to be used (e.g. binding to a mildly complex function) without consequence. I also think that if you are more relaxed towards it, when a performance problem does come around, you may not be prepared architecturally to effectively debug/refactor it.
IMO there are certainly times where using default CD will benefit the code. But, you should still take the mindset of enforcing everything be OnPush by default, and only flip it back if there is solid justification for it. That's especially the case these days, where it's so easy to make a reactive template.
There's yet another way to do `OnPush` using reified reactivity, i.e. using `Observables` and `BehaviorSubject`s instead of mutating references with new objects. This is more complex still but makes managing concurrency easy if you need to (debounce, retry, etc). It doesn't really require zone.js and is much closer to a signal based solution.
That is also possible, you can do it without NgRx too. 👍
Just my opinion based on a couple of enterprise-grade projects I've worked I think this (i.e. using Default change detection) encourages bad application architecture & component hygene. With the default setting, engineers will tend to use components instead of services for state management / manipulation, which could result in hundreds of lines of spaghetti code that handles data fetching, data management & UI interaction (no clean separation of concerns). Mutating state (as in your example) like that in components can be a nightmare to debug / test. (That being said, OnPush with markForCheck() or detectChanges() being called everywhere is even worse, but if that is something engineers try to avoid, I've found "purer" / simpler components are created).
There is also the mental model overhead of knowing when to use OnPush vs Default, rather than always following a single pattern.
The cleanest approach I've found is having services that handles data updates & provides immutable state via observables, which allows all the components to have less business logic.
You can do bad architecture and bad code with either OnPush and default change detection. You can write clean components and services with default just as well, with the added benefit that it's much more straighforward and easy to use. , it's just a myth that OnPush will help avoid this.
thank you for making this content. ive been working with angular for a few years now, yet i still get a lot of value from your content
Thank you, it's awesome to hear that 😊
I'm interested to see what you're going to say, Vasco. I ALWAYS use OnPush to keep change detection localised to the component tree segment in question rather than need the full check of the default behaviour.
This does make sense. I think the big difference is that right from the start I built with a centralised immutable store which delivers everything into components using Observables. I've also found using signal inputs since v17.2 a game changer for simplicity of component design. Thanks for this excellent explanation as always, Vasco!
Very solid arguments, thank you very much!
You're welcome Julien, I'm glad the video helped. 😊
Great points! Keep up them coming!
Thank you, will do! 😊
Great Video ! :)
Thank you, glad you enjoyed it 😊
I think the claim that using OnPush requires a vastly different way of coding components vastly overstates the changes needed. I've changed default generator to add OnPush with almost no changes ever needed. The big difference I see between my code and @AngularUniversity is that AU is using plain old container objects instead of Observables. In my experience almost all data such as Course[] is supplied from an asynchronous provider, e.g. advancedCourses$: Observable.
In the example code, I think a separate component would solve the problem. Alternatively, I think injecting the ChangeDetectorRef and marking for update would work. Have not tested either
Thank you for commenting, but that is actually maybe the main difference. OnPush makes it hard to use just plain member variables, which is a very natural programming model. OnPush forces you to either feed the data via Observables, create separate components just to have an input for things that would otherwise not be a separate component, or use ChangeDetectorRef everywhere. This is all doable, but significantly more complex than what default change detection gives you, just plain member variables without the need for Observables. 👍
@@AngularUniversity But the problem is that dynamic plain old containers just don't appear on any reasonably sized app, i.e. any app that makes API calls. If it's not making any API calls it's very likely static and change detection does not matter. The actual angular-course page makes a request to get the courses. Does it not use async? The lessonsService? If you managed that without observables, that's a lesson I'd love to learn!
@@NuncNuncNuncNunc Yes correct you don't need Obervables or the async pipe. With default change detection, you can just have a plain member variable and access it from the template.
@@AngularUniversity I think you've completely missed my point. I'll be direct - plain old javascript containers are not used for dynamic content. Since they are not used, there is no added complexity of using observables. They are already baked in. The consequence is that there is no mental overhead nor additional code overhead to always using OnPush.
Do your services on the Angular University return plain objects? If so, please, please, please make a lesson on how to that and include features like isLoading, onSuccess, onFailure, etc.
@@NuncNuncNuncNunc and just to be clear, what do you mean by Javascript containers, you mean primitive Objects and Arrays, or something else? usually my services return Promises, you can get the primitive value with async / await then assign it to a member variable.Your component data does not have to be Observables in Angular, it can be just plain data, objects and arrays as member variables. It works beautifully, very simple and intuitive. 👍 But that programming model is essentially not doable in OnPush in a practical way.
Hello, first of all, thank you for making all these amazing angular guide/best practice videos. I'm planning to refactor most part of our project code to be signal based. I'm wondering if It would be more advantageous to use onPush change detection on signal based pages/components? Thanks and more power!
If you refactor the code into signals, it will work with both OnPush and default change detection, although signals are not plugged yet into default change detection. OnPush is already integrated with signals, if you consume a signal in an OnPush template it will mark the component as dirty, just like with the async pipe. I'm personally still waiting to see what signal-based change detection will look like, before starting to refactor into signals. 👍
@@AngularUniversity I see, thanks for this info, I am using onpush change detection on my pages/components so I think this is ok.
I heard an opinion that onPush should be used most of the time to force good architecture on developer, that is to use async pipes and split components to dumb and smart so the data is passed through inputs etc and I think it is quite good point
Modifying objects and arrays in this case can be tricky indeed but I find myself not doing that most of the time as after some update on page data needs to be refreshed with DB anyways so then streams come into play and async pipes
So I think modifying objects and arrays inside inputs could be called edge cases
Interesting video anyways, I'm curious how would you respond to that 😊
it's a myth that the constraints that OnPush brings with it are somehow beneficial. Those constraints are inconvenient for the developer and come at a price. Most of the times, that complexity price is not worth paying. 👍 I think we should use the right tool for the job and not making things unnecessarily complex without any added benefit.
Thank you for a great video, as usual. I have a data table with over 100 columns and over 300 rows. The table data is partially updated multiple times per second, through a websocket connection and the speed of the app is of paramount importance. Is onPush making a difference here or not? Tried with both strategies and I do not notice a performance difference. So it is more on how performant is a material data table, rather than the Angular's change detection merit on final user experience !?
I think that this is a great example, that even with a fair amount of data, default change detection is not an issue; Usually what is harming performance in situations with large tables with a large number of DOM elements is the number of DOM elements itself, and not the change detection. I recommend trying Angular CDK virtual scrolling, it works just like ngFor - th-cam.com/video/CemKQarA2xM/w-d-xo.html 😊
Other developer on here said use on push all the time
I hope I've explained well in the video why I think we shouldn't do it: the complexity cost is not worth it in most situations. 👍
@@AngularUniversity I didn't even know it existed to be honest!! My issue now with angular is how more complex it's getting more like Java than the true front end! Patterns and now new things!!
@@anutaNYC No need to feel like you have to use it if you don't need it, the default change detection mechanism works great for most applications. 👍
@@AngularUniversity I have a change detection error because angular sees the component as null but then when I reveal the actual component on the dom it finds it and complains, the issue is I'm passing the reference to that component by input binding and I can't find the solution