Skip to content

Signal forms: Composing components without nesting the form model #65477

@Harpush

Description

@Harpush

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

forms

Description

Currently I have two models:

export interface NumberRange {
  from: number;
  to: number;
}

export interface ExtendedNumberRange extends NumberRange {
  includeMissing: boolean;
}

Using signal forms I created a component for NumberRange and because it has built in validation (like valid range) it isn't a FormValueControl and accepts a field as input and exports a schema to use with apply.

Then I wanted to create ExtendedNumberRange component using NumberRange component.
First I did:

export const extendedNumberRangeSchema = schema<ExtendedNumberRange>((path) => {
  apply(path, numberRangeSchema);
  // other validations specific to ExtendedNumberRange...
});

Which allows composing the schema nicely.
Then I wanted to create the component. At this point I got stuck... Here are the options I thought about:

  1. Change ExtendedNumberRange to be nested - but that's annoying as the server accepts a flat model and I want to avoid mapping as much as possible:
export interface ExtendedNumberRange {
  range: NumberRange;
  includeMissing: boolean;
}
  1. Accept FieldTree<ExtendedNumberRange> and pass it as is to the number range component as is. Unfortunately it fails with a type error.
  2. Accept FieldTree<NumberRange | ExtendedNumberRange> but there is no way to check which type it is as 'includeMissing' in field will be false due to proxy and anyway probably won't narrow the type correctly.

So I am stuck with option 1 which is a shame...

Here is a stackblitz with option 2 which doesn't work (comment the number range component usage in extended number range component for it to run):
https://stackblitz.com/edit/bw2bfa5z?file=src%2Fmain.ts

Proposed solution

Somehow allow composing form based components in a way that supports inheritance in model. Either fix option 2 types problem or somehow allow something along the lines of a linkedForm or maybe there is a way which I am not aware of to make 3 work with the union?

Alternatives considered

  1. Use nesting in the form model and add a mapper from model to form model and vice versa (can be annoying when the form has a large model)
  2. Use FormValueControl but then validation will be inside the component and not in the schema which will cause a lot of other problems...

Metadata

Metadata

Assignees

Type

No type

Projects

Status

No status

Relationships

None yet

Development

No branches or pull requests

Issue actions