You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Signal forms: applyEach: add index to SchemaFn arguments #67241
Which @angular/* package(s) are relevant/related to the feature request?
forms
Description
In signal forms you can validate items in an array using, for example:
constuniqueItems=schema<string[]>(items=>{applyEach(items,item=>{validate(item,({value, valueOf, index})=>{constfirstValueIndex=valueOf(items).indexOf(value());returnindex()===firstValueIndex ? null : {kind: 'duplicate',message: 'Items must be unique'};});});});
This is already a little bit messy, but quite workable.
However if you're not validating item, but item.property, you lose access to ctx.index.
For example:
constuniqueItems=schema<Array<{property: string,propertyValue: string}>>(items=>{applyEach(items,item=>{validate(item.property,({valueOf})=>{// ctx.index is not available when validating item.property});});});
You could still access the index via valueOf(items).indexOf(valueOf(item)), but this does become messy somewhat quickly.
You could also validate form.items as a whole, but if you want the error message to be applied to a specific item in the array- I dont think that's possible?
Proposed solution
applyEach could provide a second argument to its schemaFn, namely index.
Alternatively, perhaps indexOf could be added to FieldContext so ctx.indexOf(item) could be used.
Alternatives considered
As said, it is possible to valueOf(items).indexOf(valueOf(item)), that solution does feel quite a bit less elegant and has a bit of a code-smell to me.
I've since realized that treeValidator is actually a much better fit for this use-case. Index on applyEach might still be useful, but I no longer have a use-case for it that makes a compelling argument for adding it.
On second thought, it seems like stateOf() isn't propagating TPathKind, so keyInParent() is obnoxiously always string | number. This could probably be fixed.
On second thought, it seems like stateOf() isn't propagating TPathKind, so keyInParent() is obnoxiously always string | number. This could probably be fixed.
The runtime type of keyInParent and ctx.key() is always actually string (and runtime pathKeys always appears to be string[])
Activity
wimbarelds commentedon Feb 24, 2026
I've since realized that
treeValidatoris actually a much better fit for this use-case. Index on applyEach might still be useful, but I no longer have a use-case for it that makes a compelling argument for adding it.alxhub commentedon Feb 25, 2026
There's also
stateOf(item).keyInParent()which is effectivelyindexOf(item).alxhub commentedon Feb 25, 2026
On second thought, it seems like
stateOf()isn't propagatingTPathKind, sokeyInParent()is obnoxiously alwaysstring | number. This could probably be fixed.wimbarelds commentedon Feb 25, 2026
The runtime type of
keyInParentandctx.key()is always actually string (and runtimepathKeysalways appears to bestring[])rishabhdeepsingh commentedon Mar 14, 2026
Can I work on this one?
fixup! feat(forms): shim legacy NG_VALIDATORS into parseErrors for CV…
fix(forms): align runtime type of `keyInParent` with TypeScript defin…
Tweniee commentedon Sep 21, 2026
Can I work on this one?