8000 Add modelFrom(writableSignal) Function to create an input/output binding from a `writableSignal` · Issue #61419 · angular/angular · GitHub
[go: up one dir, main page]

Skip to content

Add modelFrom(writableSignal) Function to create an input/output binding from a writableSignal #61419

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

Closed
manudss opened this issue May 16, 2025 · 5 comments
Labels
area: core Issues related to the framework runtime core: reactivity Work related to fine-grained reactivity in the core framework cross-cutting: signals
Milestone

Comments

@manudss
Copy link
manudss commented May 16, 2025

Which @angular/* package(s) are relevant/related to the feature request?

core

Description

Currently, Angular provides a way to create models for two-way data binding using [(ngModel)] with new signal method model(). However, when using writableSignal from another service or library (such as a signal store or functions like linkedQueryParams or injectLocalStorage from ngxtension), there is no direct way to bind these signals to component inputs/outputs without manually synchronizing the model and the signal.

The proposed modelFrom(writableSignal) function would allow developers to create a model from a writableSignal, enabling seamless two-way data binding between the signal and component inputs/outputs. This would be analogous to the existing outputFromObservable function but for two-way binding.

Proposed solution

Introduce a new function modelFrom(writableSignal) in @angular/core that takes a writableSignal and returns a model that can be used with [(ngModel)] for two-way data binding. This function would handle the synchronization between the signal and the model, ensuring that updates to either are reflected in both.

Example Usage

import { modelFrom, signal  } from '@angular/core';

@Component(...)
class MyComponent  {
   mySignalStore = inject(MySignalStore);

   myModel = modelFrom(mySignalStore);
}

// In a component template
<my-compoent [(myModel)]="value">

Alternatives considered

Manual Synchronization: Developers can manually synchronize the model and the signal by subscribing to changes in both and updating the other accordingly. This approach is error-prone and requires boilerplate code.

The proposed modelFrom(writableSignal) function provides a clean, built-in solution that aligns with Angular's existing patterns and reduces boilerplate code.

@JeanMeche JeanMeche added area: core Issues related to the framework runtime core: reactivity Work related to fine-grained reactivity in the core framework cross-cutting: signals labels May 16, 2025
@ngbot ngbot bot added this to the needsTriage milestone May 16, 2025
@JeanMeche
Copy link
Member

There looks like to be an issue with the source of truth here.

It would be coming from both the parent (via the model input) and via the component itself.
See also #60243 which is closely related.

@alxhub
Copy link
Member
alxhub commented May 16, 2025

Hi @manudss,

Can you elaborate on what this design would accomplish that isn't possible with model? The initial example is equivalent to:

@Component({...})
class MyComponent {
  myModel = model('initial value');
}

Generally this design would require an effect to fire the change output, as there's no other way of knowing when the developer updates the source signal.

@eneajaho
Copy link
Contributor

This is related to this issue in ngxtension ngxtension/ngxtension-platform#566

@manudss
Copy link
Author
manudss commented May 16, 2025

Hi @alxhub

Yes, my example was simple, and therefore unclear. I have just updated it. It's if you have a WritableSignal that is stored elsewhere, in a service to make a signal store (if you use ngrx SignalStore for example). Or if you use other functions that work with writable signals as proposed by ngxtension: https://ngxtension.netlify.app/utilities/injectors/linked-query-param/ which allows linking a WritableSignal with query parameters.

The idea is that if you have another place where you want to have our WritableSignal, but still have it linked with the input/output of our component. This function can be interesting. Like what outputFromObservable proposes only for output.

As I understand it, the function composition is not possible for model(), the Angular compiler needs the model function for this to work. Therefore, only Angular core can offer such a function to link the model with something else. Hence this feature request.

@alxhub
Copy link
Member
alxhub commented May 16, 2025

Ahh, I follow now. In that case I would say this is really #60243.

In general, signals are designed to have a single source of truth. For input signals (including model), that source of truth is the template of the consumer, which defines an expression to compute the value of the signal based on other data.

Model signals work because their .set implementation raises an event which allows the source-of-truth in the parent component to update if desired. Otherwise, model behaves as a linked signal, with an overwritable local value.

It's not possible to implement this pattern on top of an arbitrary WritableSignal because we don't control its .set operation (and in fact, it could still change outside of someone calling its .set, like in the case of linkedSignals).

In such cases, you really do have two independent sources of truth and synchronization between them with an effect is the only option.

I'm going to close this as a duplicate of #60243.

@alxhub alxhub closed this as completed May 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: core Issues related to the framework runtime core: reactivity Work related to fine-grained reactivity in the core framework cross-cutting: signals
Projects
None yet
Development

No branches or pull requests

4 participants
0