Why I use a view model stream for my Angular templates

  Рет қаралды 33,901

Joshua Morony

Joshua Morony

Күн бұрын

Пікірлер: 96
@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
@dsldsl6460
@dsldsl6460 2 жыл бұрын
you can use combineLatest({a: obsa$, b: obsb$, c: obsc$}) instead of([obsa$, obsb$, obsc$]) and skip .pipe(map((a,b,c)=>({a,b,c})) to get the same result with cleaner code
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
Thanks! Yeah I thought this was deprecated but discovered in another comment thread the deprecation warning in VS Code was not accurate
@uziboozy4540
@uziboozy4540 2 жыл бұрын
@@JoshuaMorony use IntelliJ instead.
@namlevan2929
@namlevan2929 Жыл бұрын
Pro tip. Thanks
@ImperiumLibertas
@ImperiumLibertas Жыл бұрын
​@@uziboozy4540you mean neovim right?
@xocomil
@xocomil 2 жыл бұрын
What a fantastic overview of RxJs. You taught so many beginner-friendly concepts with great examples. This video is on my list of things to share with new Angular devs.
@guzmanoj
@guzmanoj 2 жыл бұрын
I've been doing this for a long time now with no complaints! ❤
@Szergej33
@Szergej33 2 жыл бұрын
Very good overview, your videos have been really helpful lately. We use this pattern in my job, so if a new junior dev were to start, I could just share this to get them up to speed ^^ For trivial usages like this, wehre you have 3 streams, and you pipe-map them to themselves, you can also create the object inside the combineLatest operator. Instead of passing in an array of sources, you can do combineLatest( { source1name: this.source1$, source2name: this.source2$ } ) It does exactly the same thing, just a bit less verbose to type out. Furthermore, if in your pipe you do need to use the streams ot do some data manipulation, you can access those streams by key, instead of by an array index, without the map operator.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
Thanks! I have it in my head that usage is deprecated? I haven't really looked into it though so I'll play around with this and see if I like it better :)
@Szergej33
@Szergej33 2 жыл бұрын
@@JoshuaMorony My comments keep getting deleted if I link the rxjs docs, KZbin thinks im a spam bot :D I thought the same, my IDE wrongly keeps suggesting that it is deprecated, while it is not. The old signature is deprecated, where you pass in multiple sources as multiple arguments. The Array and hte Object signatures are recommended. Same with the ForkJoin operator. // deprecated combineLatest(odd$, even$); // suggested change combineLatest([odd$, even$]); // or combineLatest({odd: odd$, even: even$})
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
@@Szergej33 Thanks for the clarification! Yeah I get that deprecation warning in the IDE too which is a bit annoying (especially for teaching it)
@Tomas-ir8xl
@Tomas-ir8xl 2 жыл бұрын
@@JoshuaMorony You can disable IDE deprecation check and use Es-Lint + eslint-plugin-deprecation instead.
@AlainBoudard
@AlainBoudard 2 жыл бұрын
But isn't that the whole CombineLatest operator deprecated, not only this signature ? Replaced with CombineLatestWith, says the doc ?
@cedi2929
@cedi2929 2 жыл бұрын
I absolutely love your channel bro. Just started working as dev fulltime, grooving into Angular and RxJs with your vidoes. Big shoutout! ❤✌
@subashbarik
@subashbarik 2 жыл бұрын
Your videos are always helpful for a beginner like me in Angular.
@CaseAhr
@CaseAhr 2 жыл бұрын
So simple, but so valuable. You help me so much with wrapping my head around this stuff. Thank you for keeping you examples relatively simple.
@yzzygomez
@yzzygomez Жыл бұрын
This is gold. Thanks mate!
@shivisuper91
@shivisuper91 2 жыл бұрын
This is quality content! Glad i found this channel
@BarrettGamingHD
@BarrettGamingHD Жыл бұрын
Awesome. I never knew about ignoreElements, I needed to know something like this existed for work!
@AlainBoudard
@AlainBoudard 2 жыл бұрын
Another great video Josh ! I find the straight declaration > instanciation very nice, because sometimes TS compiler gives us hard time declaring the proper type when using Observables with all the possible undefined outputs.
@MarcoPinheiro
@MarcoPinheiro 2 жыл бұрын
Really nice topic, thank you very much Joshua!
@dawidos0095
@dawidos0095 2 жыл бұрын
Great content, especially in these days when almost everyone claims that angular is dead etc. Keep up the good work! 💪
@billy8461
@billy8461 2 жыл бұрын
really liked this approach. I had on of the observables emitting another observable so i usetd startWith(of({})) Thanks
@jaybee6382
@jaybee6382 10 ай бұрын
The *ngrxLet directive is a lifesaver.
@NerdENerd
@NerdENerd Жыл бұрын
I prefer the patten because it is an object it is always true and because the properties are using the async pipe they are null before emitting. Much cleaner in my opinion.
@adambickford8720
@adambickford8720 Жыл бұрын
You are losing control over your concurrency as nothing is coordinating those subs. You're putting a lot of TS in the template which is a poor separation of concerns. You're also exposing a lot more of your class internals which promotes coupling. You could literally emit that exact struct from a Subject with a default value. I think this is worse in every way :shrug:
@indiasnumber1architect574
@indiasnumber1architect574 2 жыл бұрын
do more of this!! this is amazing
@slinkyfoxx
@slinkyfoxx 2 жыл бұрын
These videos are outstanding
@LucidFabrics
@LucidFabrics 2 жыл бұрын
I , at this verry moment, will be refactoring a page that receives a separate set of streams from multiple api calls into one stream and then display the a skeleton-text using only one condition. That will be fun. thanks for sharing!
@mahmoudlawendy6029
@mahmoudlawendy6029 2 жыл бұрын
Thanks for explaining it really well! I've been putting off learning soft soft cuz it looks so intimidating but now that I easily understood the
@sergiokagiema9658
@sergiokagiema9658 Жыл бұрын
Great job man!
@OLIV3R_YT
@OLIV3R_YT 2 жыл бұрын
Awesome video as always
@julienwickramatunga7338
@julienwickramatunga7338 2 жыл бұрын
Nice pattern, thank you very much!
@alextiger548
@alextiger548 2 жыл бұрын
thanks man, good stuff.! One of the best
@stepyCS2
@stepyCS2 2 жыл бұрын
Love your vids! Keep it up brotha
@vladimirlebedev00010
@vladimirlebedev00010 2 жыл бұрын
Thank you! Your content is very useful, keep uploading videos! :)
@SuperAussi3
@SuperAussi3 2 жыл бұрын
Thanks a lot...very good videos
@maks-yaremenko
@maks-yaremenko 2 жыл бұрын
very useful as always! thanks
@LarsRyeJeppesen
@LarsRyeJeppesen 2 жыл бұрын
I do the same, rxjs is so awesome
@RyanWaite28
@RyanWaite28 Жыл бұрын
This is actually smart
@rd_45
@rd_45 Жыл бұрын
Thanks josh
@angeltemelko6544
@angeltemelko6544 2 жыл бұрын
Awesome content!
@StephenMoreira
@StephenMoreira 2 жыл бұрын
Very informative.
@dmitriysahno2362
@dmitriysahno2362 8 ай бұрын
Great! 👍
@plsreleasethekraken
@plsreleasethekraken Жыл бұрын
Does using Reactive Forms for large form views change this approach? I generally just subscribe to my data from persisted storage and then set the reactive form data imperatively. At that point Reactive Forms is binding the view and model data.
@praveensripati3407
@praveensripati3407 2 жыл бұрын
learned new things, Very informative. @Joshua Morony Can you make videos regarding forms and how to handle them in an efficient way, it would be really helpful, Thanks✌.
@gautamfitness4314
@gautamfitness4314 2 жыл бұрын
Can u teach how to use nexus
@muzammiliqbal1753
@muzammiliqbal1753 2 жыл бұрын
Nice thing but the issue I believe with this approach would be if we use shareReplay for multiple subscriptions then firstly, we will have to trigger subscription again if we want to update data of template after let's say deleting some record. Secondly, we will have to call checkError again. There are solutions to this like a refresh subject in order to forcefully get data again but in the end there will be too many observeables for a basic thing.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
Do you have an example of what you mean? There shouldn't be any issues with needing to fetch data again as that's the point of using the observable streams - we aren't pulling data out of the streams to put into our vm, the entire vm is composed of streams that will update when necessary.
@behindthescenex
@behindthescenex 2 жыл бұрын
Hi Joshua! Thankyou for sharing this video. If i may ask, can you sometime covering how to unit test with this kind reactive pattern? Thankyou so much before 🙏
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
Yes not sure if I have any videos on this already, but a vid on observerSpy (which is what I mostly use to test all my observables) I think would be interesting
@romarioputra3775
@romarioputra3775 2 жыл бұрын
So viewmodel design pattern is basically combine every observable into 1 right?
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
The view model pattern is more general than just this specific context, but in general means creating some kind of object that has all of the values for your view. In this context, yes I am talking about combining everything into one observable stream that will emit the view model object.
@ventsi34
@ventsi34 2 жыл бұрын
It looks very clean but I have a question. When this is better to be used than resolvers? I think it solves the same problem.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
I don't really ever use resolvers so maybe there is some interesting patterns I'm missing, but in my mind you would only use a resolver when you need to pre-fetch some data before navigating to the page.
@Qellson
@Qellson 2 жыл бұрын
Great Job! Love your content! Just one question. Would it be better to use BehaviourSubjects with an initial value instead of combining Subjects with startWith operators?
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
I might be missing your exact meaning but sure if you can set something up as a BehaviorSubject that makes sense, but otherwise if you are dealing with an async stream that doesn't have an initial value then startWith is a good way to deal with that
@SamiullahKhan
@SamiullahKhan 2 жыл бұрын
Thanks for the work, ignoreElements are totally new for me. What do you think, what action user needs to take when there is error. Giving option of retry is one solution, is that possible vm$ stream? Or are there better solutios?
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
Yeah there's a bunch of different things you can implement with streams, you can even implement automatic retries when there is an error (e.g. try making the same request to an API 3 times before finally giving up and erroring)
@joaomarques8255
@joaomarques8255 2 жыл бұрын
Hi @Josua ! I really like this approach and it's a really nice pattern to have but don't we need to worry about performance? For example if I have a huge vm object and only one of the subject emmiting one value at some point this will cause the entire vm to emit that huge vm object with only one updated value. In other words, emmiting a entire object only because one subject emmited a value.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
This shouldn't effect the rendering of your component because, as far as I understand at least, even if the vm$ is emitting all of the values when any of them change, as long as you are using OnPush it will not trigger change detection for any components using those values as inputs (unless they have changed) as they maintain the same reference.
@valeron_1337
@valeron_1337 Жыл бұрын
I think of a use case which could potentially lead us to performance issue if we had some heavy computations inside of our derived vm$, especially if the vm$ itself was large. Thus for each emission inside combineLatest we would have to recompute everything again even though most of the output would evaluate to the same value as the previous one.
@tryhuma
@tryhuma 2 жыл бұрын
what about efficiency? one stream emission causes whole template rendering
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
It won't - if you are using OnPush only the value that changes in the vm will trigger change detection where it is used as an input, and if you aren't using OnPush then change detection is triggered for your entire component tree on every change anyway. In both cases though, it's probably important to clarify that Angular won't re-render everything in the DOM anyway, just what has changed.
@nathanalberg
@nathanalberg 2 жыл бұрын
using `vm$ = combineLatest` in webstorm is not giving me type information about the objects in the template atm... :(
@d.nickolas
@d.nickolas 2 жыл бұрын
What is the difference between forkJoin and combineLatest?
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
A forkJoin will wait for all of its input observables to complete and then emit an array containing all of their values - just once. combineLatest will emit every time there are new values, and the input observables may not necessarily complete.
@EditorialGuiasdelSur
@EditorialGuiasdelSur 2 жыл бұрын
I would like to ask you a question please?
@tleveque
@tleveque 2 жыл бұрын
Really cool Rxjs stuff here..... But I wonder, what is the advantage of this approach? It seams that it can get really complicated with a more complex case. If there is no performance improvement, I prefer to keep with more readable code to be easily maintainable. In the real world of software development, this is the key. "Maintainable". I always keep in mind what will happen if in 2 years from now, another developper has to go into this code to fix a bug or add a feature. He should be able to understand how the code is working really fast. And I don't think that kind of advance use of Rxjs is really helping.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
At least in my opinion, this makes things simpler. It makes it very explicit what data is intended to be displayed in the template, and there is one mechanism for doing that which will auto update the template as those values change. If you want to display something in the template, you add it to the vm$ stream. I think this provides a nice pattern/rule for many different devs to follow over time, rather than potentially different devs doing different things to display values in the template.
@ponderwonder
@ponderwonder 2 жыл бұрын
It creates a nice separation of "template" vs "template logic". Conceptually, I start from the template. "What's do I need to know in order to render this view in all of the states we need to support, with the simplest interface?". Then I fetch all the things I'll need (usually from API services, user inputs etc) and compose those streams together, finally mapping the data to my simple VM. It prevents you from adding a property to an API interface somewhere and cascading that down into the template. It also means we can easily keep complex logic out of the template and in the TS instead. E.g. `*ngIf="user.firstName && user.lastName && user.loaded && user.whatever"` we can just do `*ngIf="user.name"` and move the logic into the observable map().
@valeron_1337
@valeron_1337 Жыл бұрын
​@@ponderwonder I like your explanation. However, If the vw$ were more complex with more inputs to combineLatest and even more of these derived fields requiring additional pipeable operators to evaluate themselves (such as you described with map to obtain user.name) then I think we would still end up with pretty much the same mess as we never used vm$. In my opinion, the pattern in the video is very nice though it won't make much difference if we have to deal with bigger number of values inside the vm$. What are your thoughts ​ @Peter Hodges @JoshuaMorony PS. Thanks for sharing this.
@ponderwonder
@ponderwonder Жыл бұрын
@@valeron_1337 Always welcome the discussion. I think I would argue the opposite to your logic. For very simple components that have a couple of angular inputs and a simple template, using the vm pattern can feel like overkill. And yeah, you can still keep template logic in the TS by using OnChanges to map to an internal property. As the number of inputs (general inputs, not necessarily angular inputs) increases, and especially where these inputs are asynchronous and can happen over time, the reactive nature of rxjs makes things much simpler. (Think DOM events, socket events, timers, polling etc.) Without it, it's really easy to get into inconsistent states due to race conditions, things happening in orders you didn't expect etc. With reactive programming, providing you've piped your streams together correctlt, you'll always get the correct result eventually. If a stream further up the chain emits out of sequence, or twice, unexpectedly, maybe the vm is emitted twice (a mistake) but you'll still end up with the correct result. The only time I've really seen it become a mess is where people combine reactive programming with imperative patterns (e.g. using a tap and updating a property on the class, or opening a dialog via a function invocation, rather than declaratively) but this is the vm pattern being applied incorrectly rather than a problem with the vm pattern itself.
@KrycekA
@KrycekA 2 жыл бұрын
Josh, excellent video as always! I am curious to hear what you think of the following approach as an alternative to your solution: In the template, you could use the following condition: *ngIf="{greeting: greeting$ | async, user: user$ | async, count: count$ | async} as vm". I used this approach a few times on my day job
@masterlup
@masterlup 2 жыл бұрын
this is bad practice for multiple reasons: 1. make your template as lightweight and stupid as possible. Therefore its easier to change stuff in die future. 2. now you have 3 async pipes in the template vs 1 async pipe. This does not scale in terms of performance and also you're bloating your template what violates Nr1 again. Imagine you have 15 properties with your approach
@blokche_dev
@blokche_dev 2 жыл бұрын
Still valuable content. Thanks a lot. You can also use an object in combineLatest if I am not mistaken. Maybe on the latest versions only? No need to map your value anymore. const fullname$ = combineLatest({ firstname: firstname$, lastname: lastname$ });
@masterlup
@masterlup 2 жыл бұрын
this has been mentioned by dsl dsl one day earlier
@blokche_dev
@blokche_dev 2 жыл бұрын
@@masterlup Did not notice. Sorry.
@klafbang
@klafbang Жыл бұрын
You do not answer the question from the title. You just show reasons it is a bad idea.
@masterlup
@masterlup 2 жыл бұрын
rxAngular or ngrx component store
@LarsRyeJeppesen
@LarsRyeJeppesen 2 жыл бұрын
Ngrx
@DjLeonSKennedy
@DjLeonSKennedy Жыл бұрын
why are u using angular?
@kaibe5241
@kaibe5241 Жыл бұрын
What's the main benefit of this? It seems like an unnecessary step for accessing things you may already have access to.
@anj000
@anj000 Жыл бұрын
8:10 not gona lie - coming from Vue this looks... horrible. I really want to start liking Angular, but such structures seem over engineered and hard to read.
@anj000
@anj000 Жыл бұрын
It looks like solving problems, that we created in the first place. Not really getting the point of doing this.
@DawidRudzik
@DawidRudzik Жыл бұрын
biggest mistake in rxjs is error handling catchError((err) => of (err)) is such common and such ugly solution that it's surprising that no one in rxjs team came up with the idea to donst complete Observale when errors appear. Observable should be complete only in explicity way using .complete() method. Observable should be stream of errors, and success. Alternatively inside constructor whe shuld have oportunity to configure that behavior: new Subject({errorCompleteSubject: true})
@petraveryanov2572
@petraveryanov2572 2 жыл бұрын
This example is so basic that I dont see any advantage of this approach. I mean with old-style 3x subscribe I gonna have pretty same html and js wont be more complicated either... And there are some questions, how this code will look like in more advanced, more real cases: E.g. lets say count$ is an input and user$ is http get with count$ as param -- can u deal this with no subscriptions in js. E.g. u need to calculate some value based on greeting$ and count$ -- where this code goes? If you add this to combineLatest thing, then its gonna run also when userDelayed$ is emitted. etc.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
Coding reactively is a bit of a different mental model, but the general idea for the scenarios you have suggested is to derive streams in some manner using RxJS operators for whatever you want to add to the vm$ stream. For your count->user example you would have a user$ stream that is derived from the count$ stream and switchMaps to http. For greeting + count you would create a new stream with combineLatest that has both of those streams as input, then use the map operator (or whatever other operator you need) to get the result you want. All of these streams you create go into the single vm$ stream, and yes any time any of the input streams change the vm$ stream will emit all of the values, but this doesn't matter. If you are using these vm$ stream values as inputs to components the reference is maintained if the value has not actually changed, so you aren't unnecessarily triggering change detection for unchanged values.
@josepalacid
@josepalacid Жыл бұрын
Too much screen blank or useless code space wasted that could leave place to a bigger font. Mobile and vision impaired subscribers will be grateful.
@moch6459
@moch6459 2 жыл бұрын
Hoax
I only ever use *these* RxJS operators to code reactively
25:25
Joshua Morony
Рет қаралды 135 М.
Build a Chat Application with GetStream.io, Angular and Firebase
2:02:02
Decoded Frontend
Рет қаралды 19 М.
Smart Sigma Kid #funny #sigma
00:33
CRAZY GREAPA
Рет қаралды 33 МЛН
Don't underestimate anyone
00:47
奇軒Tricking
Рет қаралды 29 МЛН
99.9% IMPOSSIBLE
00:24
STORROR
Рет қаралды 20 МЛН
Tuna 🍣 ​⁠@patrickzeinali ​⁠@ChefRush
00:48
albert_cancook
Рет қаралды 45 МЛН
Linux operating system
23:27
Dr. Eman Shawky
Рет қаралды 1,3 М.
How to deeply understand Angular signals (...or anything)
10:51
Joshua Morony
Рет қаралды 3,7 М.
RxJS made my code 5x shorter... but is it better?
12:48
Joshua Morony
Рет қаралды 18 М.
WTF is a HOT observable?
9:15
Joshua Morony
Рет қаралды 17 М.
Never Get Lost In Your Buffers Again | Vim Marks
5:26
matt-savvy
Рет қаралды 8 М.
The hidden gotcha with async in Angular forms
10:37
Joshua Morony
Рет қаралды 18 М.
Why didn't the Angular team just use RxJS instead of Signals?
8:15
Joshua Morony
Рет қаралды 102 М.
WTF is "Zone.js" and is it making your app slow?
13:21
Joshua Morony
Рет қаралды 55 М.
💥 Angular Mistake #4: 🛑 STOP Avoiding Using Promises #angular
14:03
Angular University
Рет қаралды 4 М.
Should we really NEVER subscribe in Angular apps?
13:22
Joshua Morony
Рет қаралды 18 М.
Smart Sigma Kid #funny #sigma
00:33
CRAZY GREAPA
Рет қаралды 33 МЛН