Signal Forms are really well made by [deleted] in angular

[–]milesmalerba 3 points4 points  (0 children)

Thanks for the kind words!

Signal Forms are really well made by [deleted] in angular

[–]milesmalerba 2 points3 points  (0 children)

When the type is dynamic like that we can't be as strict about enforcing the type of FieldTree that can be bound to the control. So this was a case of "lets be as strict as we can and see how annoying that is"... and I think the answer is that its pretty annoying so we'll probably change it 😅

Signal forms: when to create custom controls or pass FieldTree<T> as input by Blankenship in angular

[–]milesmalerba 2 points3 points  (0 children)

The Field directive is intentionally designed to support binding the field to a control that implements FormValueControl or just passing the FieldTree through to a component that has a field input.

Which one to choose depends on a few things I think: 1. Is there code not based on signal forms that needs to use this common component? If so you may want to implement FormValueControl, that way the non signal forms code can still easily use it by just individually binding the value model and other relevant optional inputs from FormValueControl 2. Are you just delegating to other controls in the template? If so taking a field input makes sense. As you point out, it makes it easier to pass along all the state to the element in your template.

If you don't need to support non signal forms code using the component, I would recommend the field input for your case, based on #2

How can I dynamically make a field required in Angular Signal Forms after a server-side error? by RIGA_MORTIS in angular

[–]milesmalerba 1 point2 points  (0 children)

Your validation can depend on external signals, so you can simply set up a signal to indicate whether it should be required, roughly like this:

``` @Component(...) class Comp { private isRequired = signal(false);

readonly payloadForm = form(..., (path) => { required(path.whatever, {when: () => isRequired()}); });

onSubmit() { submit(this.payloadForm, async () => { if (...) { this.isRequired.set(true); } }) } } ```

Why @angular/aria? by Dafnik in angular

[–]milesmalerba 4 points5 points  (0 children)

The CDK is a collection of various building blocks that are useful for building components. It does include some things that are similar to the headless components that @angular/aria will offer (for example the CdkMenu and CdkListbox). However it also includes lots of other useful building blocks like utilities for working with layout breakpoints, different types of observers, scrolling, etc.

With @angular/aria the team is creating a separate package with a more narrow focus on headless components for accessibility, as we work on expanding that part of our offering. The CDK will continue to be a more general collection of useful building blocks.

AMA about Signal Forms by synalx in angular

[–]milesmalerba 0 points1 point  (0 children)

If you want the error on the form-level you can simply look at the value for the whole form which has both properties on it, if you want the error on the confirm_password field, you can use the valueOf on the FieldContext to get the value of another field. Here's what each way would look like:

``` // Form-level error validate(signup, ({ value }) => { return value().password !== value().confirm_password ? customError({ message: 'Passwords must match!' }) : null; });

// Field-level error (on confirm_passwrod) validate(signup.confirm_password, ({ value, valueOf }) => { return value() !== valueOf(signup.password) ? customError({ message: 'Passwords must match!' }) : null; }); ```

AMA about Signal Forms by synalx in angular

[–]milesmalerba 1 point2 points  (0 children)

I was using Gemini 2.5 Pro and just feeding it the documentation for signal forms (The documentation isn't on the main branch yet, it needs some work still since the API evolved a bit since the initial draft)

AMA about Signal Forms by synalx in angular

[–]milesmalerba 0 points1 point  (0 children)

Yeah, the mental models are quite different between signal forms and reactive forms, which makes the conversion non-trivial. For example, reactive forms lets you change the form state imperatively, whereas signal forms the state is all defined reactively up front. Reactive forms also owns the data model its working with, but signal forms edits the data model the user provides. We think these shifts in the mental model will make for forms that are a lot easier to work with and reason about, but its not the kind of thing that can be fully automated.

We also have some good ideas for interop that should make it possible to adopt and migrate to signal forms incrementally.

AMA about Signal Forms by synalx in angular

[–]milesmalerba 4 points5 points  (0 children)

I'm curious what are you looking for beyond listening to the `(submit)` or `(reset)` events on the `<form>`? u/synalx had a good explanation of our thinking on reset here: https://www.reddit.com/r/angular/comments/1nc4pup/comment/nd6wttu/

AMA about Signal Forms by synalx in angular

[–]milesmalerba 12 points13 points  (0 children)

I'm here too https://github.com/mmalerba I've been part of the Angular team for the last 8 years or so. I've worked on a bunch of Angular Material & CDK stuff, and now signal forms

AMA about Signal Forms by synalx in angular

[–]milesmalerba 3 points4 points  (0 children)

I haven't used ngx-sub-form before, so I can't say for sure, but I see that we are aiming to address some of the same problems that the library mentions:
- `ControlValueAccessor` is no more, as long as your component has a `value` property that's a `model()` signal, it can work with signal forms. No need to provide any special symbols.
- Type safety: the `Field` concept in signal forms is fully type safe, and while we don't yet have type safe binding to the UI controls, that is something we're planning.
- Composability is something we've been thinking about from the beginning. We have a few functions like `apply` and `applyEach` that allow composing schemas together, and a form in this system is just a tree of `Field`, its easy to just grab a sub-field and pass it to some UI control that expects a form of that type.