Skip to content

docs: add new signal forms - form submission guide#67862

Open
bencodezen wants to merge 1 commit intoangular:mainfrom
bencodezen:docs/signal-forms-form-submission-guide
Open

docs: add new signal forms - form submission guide#67862
bencodezen wants to merge 1 commit intoangular:mainfrom
bencodezen:docs/signal-forms-form-submission-guide

Conversation

@bencodezen
Copy link
Contributor

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.dev application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

@bencodezen bencodezen requested review from JeanMeche and kirjs March 25, 2026 14:45
@bencodezen bencodezen added action: review The PR is still awaiting reviews from at least one requested reviewer target: patch This PR is targeted for the next patch release area: docs Related to the documentation adev: preview labels Mar 25, 2026
@ngbot ngbot bot added this to the Backlog milestone Mar 25, 2026

The `FormRoot` directive handles three things automatically when bound to a `<form>` element:

1. **Sets `novalidate`** — Disables the browser's built-in validation so Signal Forms manages validation instead
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2. **Prevents default** — Stops the browser from navigating on form submission
3. **Calls `submit()`** — Triggers the submission flow when the user submits the form

NOTE: The `FormRoot` directive sets `novalidate` automatically. You do not need to add it manually when using `FormRoot`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

Suggested change
NOTE: The `FormRoot` directive sets `novalidate` automatically. You do not need to add it manually when using `FormRoot`.
NOTE: The `FormRoot` directive sets the `novalidate` attribute on the `form` element automatically. You do not need to add it manually when using `FormRoot`.

@github-actions
Copy link

Deployed adev-preview for db2220a to: https://ng-dev-previews-fw--pr-angular-angular-67862-adev-prev-npev4evt.web.app

Note: As new commits are pushed to this pull request, this link is updated after the preview is rebuilt.


The `submit()` function runs through a specific sequence:

1. **Mark interactive fields as touched** — This surfaces any validation errors that were hidden because the user hadn't interacted with the field yet. Hidden, disabled, and readonly fields are skipped.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of manually enumerating, we can use 1. so Markdown handles it automatically

}
```

Side effects like navigation, toast notifications, or resetting the form belong _after_ the `await` — not inside the `action` function. The `action` is for communicating with the server and returning errors. Everything else happens in the calling code.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the rationale for this rule?

And most importantly, how would one respect it when handling the submission by specifying the submission.action option when defining the form?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the toast/navigation typically needs information that is obtained inside the action function. So respecting that rule would make code weird:

async onSave() {
  let contactId: string | undefined = undefined;
  const success = await submit(this.contactForm, async (field) => {
    contactId = await fetchContact(field().value());
  });

  if (success && contactId) {
    this.router.navigate(['/confirmation', contactId]);
  }
}

vs.

async onSave() {
  await submit(this.contactForm, async (field) => {
    const contactId = await fetchContact(field().value());
    this.router.navigate(['/confirmation', contactId]);
  });
}

</button>
```

Once the `action` function succeeds or returns an error, the `submitting()` signal automatically resets back to `false`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really related to this PR, but given that multiple concurrent submissions are probably something that should generally be avoided, shouldn't that be handled automatically by the form? I.e. shouldn't the form prevent the action from being called if it's currently submitting (similarly to what it does when the form is invalid)?

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

Labels

action: review The PR is still awaiting reviews from at least one requested reviewer adev: preview area: docs Related to the documentation target: patch This PR is targeted for the next patch release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants