Skip to content

Signal forms: applyEach: add index to SchemaFn arguments #67241

Open

Description

@wimbarelds

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:

const uniqueItems = schema<string[]>(items => {
  applyEach(items, item => {
    validate(item, ({value, valueOf, index}) => {
      const firstValueIndex = valueOf(items).indexOf(value());
      return index() === 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:

const uniqueItems = 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.

Activity

  1. wimbarelds commented on Feb 24, 2026

    @wimbarelds
    Author

    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.

  2. reopened this on Feb 24, 2026
  3. added this to the needsTriage milestone on Feb 24, 2026
  4. alxhub commented on Feb 25, 2026

    @alxhub
    Member

    There's also stateOf(item).keyInParent() which is effectively indexOf(item).

  5. reopened this on Feb 25, 2026
  6. alxhub commented on Feb 25, 2026

    @alxhub
    Member

    On second thought, it seems like stateOf() isn't propagating TPathKind, so keyInParent() is obnoxiously always string | number. This could probably be fixed.

  7. wimbarelds commented on Feb 25, 2026

    @wimbarelds
    Author

    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[])

  8. rishabhdeepsingh commented on Mar 14, 2026

    @rishabhdeepsingh
    Contributor

    Can I work on this one?

  9. added 2 commits that reference this issue on Apr 2, 2026
    5753f71
    bb6d010
  10. Tweniee commented on Sep 21, 2026

    @Tweniee
    Contributor

    Can I work on this one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions