Look grrat, but I would be interested in an example that shows how you would handle bigger amounds of data, as you mentioned in the video. And it would be interesting seeing how you would hamdle loading, error and mybe even retrys.
It's not this particular example but I do have a separate video that uses the same approach and covered errors/retries/pagination in more depth: th-cam.com/video/44_IcGPKQ_M/w-d-xo.html
youre the very best, thank you so much! great video and really helped me to understand the approach even better ❤ would love to see another one about that topic
Really interesting, we're having some serious brainstormings at work about those kind of problems (state management). It's in an old Angular 8 app, but your principles of having sources of data "raining" down the app and of coding in a reactive way can still apply.
@@JoshuaMorony I was thinking about a full feature, covering all aspects of the front-end CRUD, error handling, loading state, retry if fail, ..etc. This would be so great, as it will show us the thinking process and how to implement fully reactive feature. Thanks in advance ☺️
Great stuff Josh, I'd personally like to see more examples of this but there larger data where it would need to be paginated and how we would handle the state. (Some elegant solutions)
Great video, just what i was looking for a few weeks ago! I would also like to see how you handle relational data, say for example a table object that relates to columns, rows and cells, how to keep track of everything? lets say if you create a table it should also create the first row, cell and column, but you could also create those manually after the table is in place.. how would you do it in an efficient and reactive way?
@JoshuaMorony Perhaps it is explained in more detail in one of the other videos, but why are the source modeled as behaviorSubjects and not as signals? Whenever an action like an update or add is pushed / set on the signal, it would be possible to react to it using effects? If you need async reactivity, you can use toObservable and use rxjs to do the http call. The result can be subscribed to by using the toSignal rxjs interop function. Do you see any flaws with this approach?
A bit of a nit but they are Subjects not BehaviorSubjects, so specifically for representing events not storing state. RxJS/subjects are a better mechanism for representing events so the flow from RxJS to signals works better. For example if I were to try to represent a source as a signal, and an event happens where the same data might be emitted twice (the source might just happen to have the same data twice or it might just be a void type of source), the signal won't actually be triggered because it needs to be a new value each time. This could be worked around perhaps by wrapping the value in something that will always have a unique value, but it's just not really what signals are intended to be used for.
But with this merge when checklistAdded emit, your have two api call... Maybe is better to take result in the switchmap and avoid duplicate api call for checklistAdded case ?
Do you mean because we have one request to perform the action (e.g. adding the checklist) and another to refetch the data after any action occurs, whereas we could use the response from the server instead of refetching? Yes you could do this if you wanted to avoid the request to re-fetch, it makes the code slightly more complex but improves performance (there are more improvements we could make like that too)
Hi Josh! Thanks for the video, really nice, I love how well you explain things! I've been checking the github repo and haven't seen any loading indicators or similar. I guess that there's no feedback while waiting for the backend and the lists just change once the refetch is done, is that right? How would you manage this so the user gets some feedback about what's happening while allowing to still make changes if loading?
For situations where I want to show some kind of loading indicator I will have the initial fetch action (e.g. in this case a fetch begins when add/edit/remove are triggered) update the state signal with something like "status: 'loading'" then when any of those merged streams which represent completion emit (e.g. checklistAdded$) I would update the state signal to "status: 'success'" or "status: 'error'". Then I can use that state as the basis for displaying whatever kind of loading indicators I like. Here's an example of that in another app: github.com/joshuamorony/angularstart-chat/blob/main/src/app/auth/login/data-access/login.service.ts
Awesome stuff! Have you or will reflect some changes or fixes you showed in earlier videos to the angularstart course? Also ngrxstart one day? :p Would really love to see your full approach and have a nice reference project to check when I'm stuck on my work code :) And yes for more backend content!!
Yeah I'll be doing a big update to Angular Start to incorporate all the more recent stuff, I was hoping to wait for signal based components/the rest of the signals APIs, but we already have most of the stuff now so I'll likely just do a v18 update after it is released
@JoshuaMorony I have a follow up question. When one service needs to react to another service, does the service depend on the signal in the other state or best expose the state as an observable. To make it more concrete: If you have an authentication service that tracks the currently logged in user (or anonymous if not logged in) and you have another service, the ProductService that needs to load data from the backend depending on the currently logged in user. Does the product service use the userSignal or does the Authentication service expose the observable for the current user. Or is it all up to flavor? Tnx
I think both are fine - generally speaking I prefer to avoid observable -> signal -> observable and instead the ProductService can just react to the same event/stream that is setting the signal in the AuthService. But, if you decide on an architecture where all that the AuthService exposes publicly is the state signal, I think it's fine to have a new source in your ProductService which uses toSignal.
I like this one, the change to the single subscribe was sexy. One thing that is bothering me though...will You ever (maybe as a side video) show how could this be converted to the ngrx signal store?
Possibly - I'm not actually using Signal Store myself right now, but I think it will likely become the defacto NgRx approach so is definitely worth covering
@@jordanking3715 variations on the approach in the video, which are inspired by state adapt but I'm not actually using state adapt. The approach in the video is my "bare bones" approach, but more typically I will also incorporate connect from ngxtension or signalSlice (also ngxtension)
Is that just to avoid syncing the data after the rest requests using the subscribers to avoid imperative style ? Why not just check if the request failed or succeeded and then update the our signal based on that, would this not work ? I know you tried making the flow as declarative as possible, but I am just asking if this way would also work
Do you mean essentially triggering a request from within the subscribe of each request (could also have the server just respond with the data required after each request) and update the state signal from there? Yes, you could do that but as you hinted at its more imperative. I like the declarative style because we just define the data stream once, and it automatically refetches whenever any of its dependencies emit (plus the other benefits of declarative like it being easier to see how/when the data is fetched)
@@JoshuaMorony Thanks Joshua, yes that's exactly what I meant.. but as you said declarative style is more flexible but there is always a price that has to be paid 😀 in this case ot could be performance depending on the nature of data and other metrics... Keep up the good work 👏 🙌
Great content ! i have a little question (not related to this specific video), is using an angular service as a store instead of using ngrx a viable option ? Or should we always consider using ngrx for managing state in a professionnal web app? Thanks
It is certainly viable, I'm not using NgRx here for example. The good thing about a state management library is that it generally comes with opinions on how to go about managing state, so if you are rolling your own you should ideally have some sense of how/why you are managing state
Make the data be a computed http request from the ActivatedRoute.queryParams. Every time the params change, the request will be sent again and therefore the computed data will update.
Generally you just start with whatever it is you want to react to and pipe off of that. So you might start with a stream of your query params, and then switchMap to the get request
Your solution is OK from a technical point of view, but I guess using libraries such as ngrx/signal-store lead to a cleaner codebase that can be shared across different developers since everybody is going to be using the same architechture/concepts instead of building each one the way they believe is better.
I'm not against Signal Store (I think it's good) but this isn't really an ad-hoc approach, it's essentially the redux pattern with a declarative approach. We have actions that are handled by reducers that update state, and side effects if necessary via signal effects. It's just implemented directly using framework primitives/RxJS.
After using HTMX and AlpineJS for frontend and taking a brake from angular, seeing this monstrosity makes me question why i ever used angular in the first place, god damn.
Why to subscribe in a service instead of exposing streams with toSignal? Subscribing in service does not convince me, even with untilDestroy because (correct me if I'm wrong) singleton in angular app will never be destroyed
I talk more about this in this video: th-cam.com/video/R4Ff2bPiWh4/w-d-xo.html - in short, it provides more flexibility with the signals state management (without having to deal with more complex aspects of RxJS/scan). I do sometimes use toSignal though, but for more complex state I will do this manual subscribe approach (which I would typically hide via using some utility like connect or signalSlice from ngxtension). It doesn't matter if this subscribe is in a singleton service, this subscription is supposed to keep running for the entire life of the app.
Next newsletter goes out tomorrow: mobirony.ck.page/4a331b9076
We need more of such real world CRUD examples!
Yes please extend this series. Especially for authentication! I just love your videos!
Look grrat, but I would be interested in an example that shows how you would handle bigger amounds of data, as you mentioned in the video. And it would be interesting seeing how you would hamdle loading, error and mybe even retrys.
It's not this particular example but I do have a separate video that uses the same approach and covered errors/retries/pagination in more depth: th-cam.com/video/44_IcGPKQ_M/w-d-xo.html
youre the very best, thank you so much! great video and really helped me to understand the approach even better ❤
would love to see another one about that topic
Really interesting, we're having some serious brainstormings at work about those kind of problems (state management).
It's in an old Angular 8 app, but your principles of having sources of data "raining" down the app and of coding in a reactive way can still apply.
I did something similar on ngrx component store. The whole solution looks like spring boot crud repository. It saved soo much time for me.
Thanks for your tutorials . They are awesome 👏
The trick is knowing the few instances for when to deviate from the reactive/declarative context.
Great video, Thanks a lot
it would be very nice if you made a video showing the whole flow of data and the process with more details.
Any particular parts you want to know more about?
@@JoshuaMorony I was thinking about a full feature, covering all aspects of the front-end CRUD, error handling, loading state, retry if fail, ..etc.
This would be so great, as it will show us the thinking process and how to implement fully reactive feature.
Thanks in advance ☺️
Great stuff Josh, I'd personally like to see more examples of this but there larger data where it would need to be paginated and how we would handle the state. (Some elegant solutions)
It's a slightly different example, but this video covers pagination: th-cam.com/video/44_IcGPKQ_M/w-d-xo.html
Great video, just what i was looking for a few weeks ago!
I would also like to see how you handle relational data, say for example a table object that relates to columns, rows and cells, how to keep track of everything?
lets say if you create a table it should also create the first row, cell and column, but you could also create those manually after the table is in place.. how would you do it in an efficient and reactive way?
@JoshuaMorony Perhaps it is explained in more detail in one of the other videos, but why are the source modeled as behaviorSubjects and not as signals? Whenever an action like an update or add is pushed / set on the signal, it would be possible to react to it using effects? If you need async reactivity, you can use toObservable and use rxjs to do the http call. The result can be subscribed to by using the toSignal rxjs interop function. Do you see any flaws with this approach?
A bit of a nit but they are Subjects not BehaviorSubjects, so specifically for representing events not storing state. RxJS/subjects are a better mechanism for representing events so the flow from RxJS to signals works better. For example if I were to try to represent a source as a signal, and an event happens where the same data might be emitted twice (the source might just happen to have the same data twice or it might just be a void type of source), the signal won't actually be triggered because it needs to be a new value each time. This could be worked around perhaps by wrapping the value in something that will always have a unique value, but it's just not really what signals are intended to be used for.
@@JoshuaMorony tnx for the explanation
@JoshuaMorony what do you use to draw such diagrams?
Excalidraw
But with this merge when checklistAdded emit, your have two api call... Maybe is better to take result in the switchmap and avoid duplicate api call for checklistAdded case ?
Do you mean because we have one request to perform the action (e.g. adding the checklist) and another to refetch the data after any action occurs, whereas we could use the response from the server instead of refetching? Yes you could do this if you wanted to avoid the request to re-fetch, it makes the code slightly more complex but improves performance (there are more improvements we could make like that too)
Great video ❤
Great video!, sorry for the off topic question but which vim theme are you using?
tokyodark :)
Hi Josh! Thanks for the video, really nice, I love how well you explain things!
I've been checking the github repo and haven't seen any loading indicators or similar. I guess that there's no feedback while waiting for the backend and the lists just change once the refetch is done, is that right? How would you manage this so the user gets some feedback about what's happening while allowing to still make changes if loading?
For situations where I want to show some kind of loading indicator I will have the initial fetch action (e.g. in this case a fetch begins when add/edit/remove are triggered) update the state signal with something like "status: 'loading'" then when any of those merged streams which represent completion emit (e.g. checklistAdded$) I would update the state signal to "status: 'success'" or "status: 'error'". Then I can use that state as the basis for displaying whatever kind of loading indicators I like. Here's an example of that in another app: github.com/joshuamorony/angularstart-chat/blob/main/src/app/auth/login/data-access/login.service.ts
Thanks Josh!
Awesome stuff! Have you or will reflect some changes or fixes you showed in earlier videos to the angularstart course?
Also ngrxstart one day? :p Would really love to see your full approach and have a nice reference project to check when I'm stuck on my work code :)
And yes for more backend content!!
Yeah I'll be doing a big update to Angular Start to incorporate all the more recent stuff, I was hoping to wait for signal based components/the rest of the signals APIs, but we already have most of the stuff now so I'll likely just do a v18 update after it is released
@JoshuaMorony I have a follow up question. When one service needs to react to another service, does the service depend on the signal in the other state or best expose the state as an observable. To make it more concrete: If you have an authentication service that tracks the currently logged in user (or anonymous if not logged in) and you have another service, the ProductService that needs to load data from the backend depending on the currently logged in user. Does the product service use the userSignal or does the Authentication service expose the observable for the current user. Or is it all up to flavor? Tnx
I think both are fine - generally speaking I prefer to avoid observable -> signal -> observable and instead the ProductService can just react to the same event/stream that is setting the signal in the AuthService. But, if you decide on an architecture where all that the AuthService exposes publicly is the state signal, I think it's fine to have a new source in your ProductService which uses toSignal.
@@JoshuaMorony cool, tnx for the confirmation. Keep up the great work, your work inspires me a lot to try to do my frontend dev better 🙏
I like this one, the change to the single subscribe was sexy.
One thing that is bothering me though...will You ever (maybe as a side video) show how could this be converted to the ngrx signal store?
Possibly - I'm not actually using Signal Store myself right now, but I think it will likely become the defacto NgRx approach so is definitely worth covering
@@JoshuaMorony what are you using? state adapt or your own custom built state management?
@@jordanking3715 variations on the approach in the video, which are inspired by state adapt but I'm not actually using state adapt. The approach in the video is my "bare bones" approach, but more typically I will also incorporate connect from ngxtension or signalSlice (also ngxtension)
do you have video about signal sore?
Not yet but people are asking so I'll probably do one soon
just brilliant 👍
Is that just to avoid syncing the data after the rest requests using the subscribers to avoid imperative style ? Why not just check if the request failed or succeeded and then update the our signal based on that, would this not work ? I know you tried making the flow as declarative as possible, but I am just asking if this way would also work
Do you mean essentially triggering a request from within the subscribe of each request (could also have the server just respond with the data required after each request) and update the state signal from there? Yes, you could do that but as you hinted at its more imperative. I like the declarative style because we just define the data stream once, and it automatically refetches whenever any of its dependencies emit (plus the other benefits of declarative like it being easier to see how/when the data is fetched)
@@JoshuaMorony Thanks Joshua, yes that's exactly what I meant.. but as you said declarative style is more flexible but there is always a price that has to be paid 😀 in this case ot could be performance depending on the nature of data and other metrics...
Keep up the good work 👏 🙌
Great content ! i have a little question (not related to this specific video), is using an angular service as a store instead of using ngrx a viable option ? Or should we always consider using ngrx for managing state in a professionnal web app? Thanks
It is certainly viable, I'm not using NgRx here for example. The good thing about a state management library is that it generally comes with opinions on how to go about managing state, so if you are rolling your own you should ideally have some sense of how/why you are managing state
great video! super clear explanation as always! one note, at 0:30, how is "get" call the Create part of CRUD? and why is the "post" call a Read?
It was probably just a mistake
@@bric305 yep didn't realise they were out of order
@@JoshuaMorony oooh, that's what I thought, but I've learned so much from your videos I wondered if I missed something 😅
How can I refetch data when quey params are changed?
Make the data be a computed http request from the ActivatedRoute.queryParams. Every time the params change, the request will be sent again and therefore the computed data will update.
Generally you just start with whatever it is you want to react to and pipe off of that. So you might start with a stream of your query params, and then switchMap to the get request
Your solution is OK from a technical point of view, but I guess using libraries such as ngrx/signal-store lead to a cleaner codebase that can be shared across different developers since everybody is going to be using the same architechture/concepts instead of building each one the way they believe is better.
I'm not against Signal Store (I think it's good) but this isn't really an ad-hoc approach, it's essentially the redux pattern with a declarative approach. We have actions that are handled by reducers that update state, and side effects if necessary via signal effects. It's just implemented directly using framework primitives/RxJS.
After using HTMX and AlpineJS for frontend and taking a brake from angular, seeing this monstrosity makes me question why i ever used angular in the first place, god damn.
Bro you got a job ... I really wanna get out of Angular as well
Why to subscribe in a service instead of exposing streams with toSignal?
Subscribing in service does not convince me, even with untilDestroy because (correct me if I'm wrong) singleton in angular app will never be destroyed
I talk more about this in this video: th-cam.com/video/R4Ff2bPiWh4/w-d-xo.html - in short, it provides more flexibility with the signals state management (without having to deal with more complex aspects of RxJS/scan). I do sometimes use toSignal though, but for more complex state I will do this manual subscribe approach (which I would typically hide via using some utility like connect or signalSlice from ngxtension). It doesn't matter if this subscribe is in a singleton service, this subscription is supposed to keep running for the entire life of the app.
more backend