-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: deepWritableSignal
#4582
Comments
Hello! 1. Just a clarification, in case I miss or don't understand some parts.In this example ("Default Use Case") I made some edits (marked with ⬅️), please let me know where I'm wrong and why:
Edits in the template:I think that we should update the binding when Edits in the component:Here I'm almost certain I missed some details, but maybe not :) 2. Linked signals in a protected store:I think it should be implicit, because with an explicit approach, when that flag is set to false, things just will not work. |
A few questions came to my mind when I saw this proposal:
In the following example, const form = deepWritable({
user: { set: 0, update: 0 },
});
const form = signalState(
{ firstName: 'John', lastName: 'Lennon' },
{ writable: true },
);
form.lastName.set('Mayer'); |
@markostanimirovic, we can't read the value of a signal without calling a function, and getters here are not a solution, because then we will not be able to bind a signal to So it will be form().user().set.set(1) or form().user().set.update(v => !v) Then, to read this value: {{ form().user().set() }} To bind:
|
Hi guyes, Instead of just having a writeable or updateable signal I would like to extend the discussion to a "DeepPatchableSignal". Instead of just writing back single properties, we could also update full or parts of an object. Using the example we have so far in this thread, according to my proposal we should have the following options to work with the state: const user = toDeepPatchableSignal(store.user);
// patch parts of an object
user.patch({name: 'Max'});
// patch/update the full object
user.patch({id: 1, name: 'Max'});
// navigate down to deeper levels and be able to do the same
user.name.patch('John'); The goal is, that the patch function always take an From my point of view My current implementation can be found here: Currently I am calling my withMethods((store: any) => {
const patchableUser = toDeepPatchableSignal<User>(newVal => patchState(store, { user: newVal }), store.user);
return {
getUserAsPatchable: (): DeepPatchableSignal<User> => {
return patchableUser ;
}
}) To be able to reuse this logic as easy as possible is put all this into a generic signal store feature you can find here: Would be really happy to see support of something similar build directly into signalStore. I would also offer to support during the implementation or the transfer of the ideas of my current solution. |
👋 @e-oz, thanks for your comments. Here are my answers.
If we call the value of the user signal, we just get the user. With just
Thanks for pointing that out. I've updated the RFC, this was typo of mine
Yes, when user's changes the firstname will be updated automatically.
I am also lending towards it. |
If a nested object has a property like
I don't see the need but I saw that my RFC used the |
I like the idea, but I think adding a What do you think about integrating that into const UserStore = signalStore(
{protectedState: false},
withState({user: {
id: 1,
name: 'Konrad'
}})
); and then within the store: patchState(store => store.user, {id: 2}) That would be another PR though. |
@rainerhahnekamp this is a great 🚀 |
Hi @rainerhahnekamp, firstly thank you, this is a really cool idea. Secondly, here are a few thoughts of mine:
|
Perhaps some initial implementation would show us what is possible and what is not 👀 |
@e-oz I agree. I haven't seen a complete objection so far. We can process with a prototype and gather feedback on that. |
I think this is not of help to the ones who need this in template dirven forms approach. Here you want to mutate the state easily from the outside. Also in other cases i see this need again and again. So I believe the 'deep patchable signal' should be availalbe from outside the store. Otherwise we need to write wrapper methods again and again. |
No, it really isn't. It was meant to be a good feature for That being said, we pause this RFC because we see the use case only for forms at the moment. Given that we will get a SignalForm in the future, we don't want to introduce a feature that has to be deprecated in 2 or 3 majors. If you can come up with examples other than forms, we could start re-considering it. |
Update 10.12.2024: We’ve decided to pause this RFC for now, as the primary use case seems limited to forms. With the anticipated introduction of SignalForm in the future, we aim to avoid introducing a feature that might need deprecation in just 2–3 major releases.
However, if you can provide compelling examples of use cases beyond forms, we would be open to revisiting this proposal.
Which @ngrx/* package(s) are relevant/related to the feature request?
signals
Information
Problem
As Signal adoption grows, we anticipate that APIs will increasingly require Signals.
Type
Signal
will not cause any issues for the SignalStore, butWritableSignal
will.A good example we have already today, are Template-driven forms.
We have to manually create a
WritableSignal
for each field, which doesn’t scale well.Proposed Solution
deepWritableSignal
makes all nested properties in an object literal within aWritableSignal
intoWritableSignal
s themselves. This approach matches the behavior ofdeepComputed
, which can also be used as standalone.deepWritableSignal
can also be applied to an unprotected SignalStore and to the state returned bysignalState
. That would be the typesWritableSignalSource
andSignalState
.Example
Default Use Case
With the combination of
linkedSignal
, we provide a significant DX improvement without compromising the state protection:Unprotected SignalStore
For an unprotected Signal Store
For
signalState
Potential Extensions
Due to the protected state, every Signal from the
SignalStore
needs to be mapped to the typeWritableSignal
.To address this, we could extend
deepWritableSignal
with an additional parameter that internally applieslinkedSignal
. Alternatively, we could implement an implicitlinkedSignal
ifdeepWritableSignal
doesn’t receive aWritableSignal
.Version 1: Explicit
linkedSignal
Version 2: Implicit
linkedSignal
Describe any alternatives/workarounds you're currently using
Alternatively, we could wait for Angular to introduce a DeepWritable. Until then, developers have to do more manual work.
I would be willing to submit a PR to fix this issue
The text was updated successfully, but these errors were encountered: