-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #466 from CrowdStrike/expose-state-from-headless-form
Expose state from headless form
- Loading branch information
Showing
11 changed files
with
842 additions
and
342 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@crowdstrike/ember-toucan-form': minor | ||
--- | ||
|
||
Exposes validationState, submissionState, isInvalid and rawErrors from the HeadlessForm component |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Async state | ||
|
||
Submit this form with a valid email, and with the same email again, to see how it disables the submit button, changes its label, and shows error messages coming from the "backend": | ||
|
||
```hbs template | ||
<ToucanForm @onSubmit={{this.handleSubmit}} as |form|> | ||
<form.Field @name='email' as |field|> | ||
<div class='my-2 flex flex-col'> | ||
<field.Label>Email</field.Label> | ||
<field.Input | ||
@type='email' | ||
placeholder='Please enter your email' | ||
class='border rounded px-2' | ||
/> | ||
</div> | ||
</form.Field> | ||
<button type='submit' disabled={{form.submissionState.isPending}}> | ||
{{if form.submissionState.isPending 'Submitting...' 'Submit'}} | ||
</button> | ||
{{#if form.submissionState.isResolved}} | ||
<p>We got your data! 🎉</p> | ||
{{else if form.submissionState.isRejected}} | ||
<p>⛔️ {{form.submissionState.error}}</p> | ||
{{/if}} | ||
</ToucanForm> | ||
``` | ||
|
||
```js component | ||
import Component from '@glimmer/component'; | ||
import { action } from '@ember/object'; | ||
|
||
export default class MyFormComponent extends Component { | ||
saved = []; | ||
|
||
@action | ||
async handleSubmit({ email }) { | ||
// pretending something async is happening here | ||
await new Promise((r) => setTimeout(r, 3000)); | ||
|
||
if (!email) { | ||
throw new Error('No email given'); | ||
} | ||
|
||
if (this.saved.includes(email)) { | ||
// Throwing this error will cause the form to yield form.submissionState.isRejected as true | ||
throw new Error(`${email} is already taken!`); | ||
} | ||
|
||
this.saved.push(email); | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
--- | ||
title: Async state | ||
order: 5 | ||
--- | ||
|
||
# Managing asynchronous state | ||
|
||
toucan-form knows about two events that can be asynchronous: | ||
|
||
- **validation** will often be synchronous, but you can also use the ember-headless-form [asynchronous validations](https://ember-headless-form.pages.dev/docs/validation/custom-validation#asynchronous-validation) for e.g. validating data on the server | ||
- **submission** is most often asynchronous when e.g. sending a `POST` request with your form data to the server | ||
|
||
To make the form aware of the asynchronous submission process, you just need to return a Promise from the submit callback passed to [`@onSubmit`](https://ember-headless-form.pages.dev/docs/usage/data#getting-data-out). | ||
|
||
ember-headless-form will then make the async state of both these events available to you in the template. This allows for use cases like | ||
|
||
- disabling the submit button while a submission is ongoing | ||
- showing a loading indicator while submission or validation is pending | ||
- rendering the results of the (either successful or failed) submission, after it is resolved/rejected | ||
|
||
To enable these, the form component is yielding `validationState` and `submissionState` objects with these properties: | ||
|
||
- `isPending` | ||
- `isResolved` | ||
- `isRejected` | ||
- `value` (when resolved) | ||
- `error` (when rejected) | ||
|
||
These derived properties are fully reactive and typed, as these are provided by the excellent [ember-async-data](https://github.com/tracked-tools/ember-async-data) addon. Refer to their documentation for additional details! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
--- | ||
title: Native validation | ||
order: 3 | ||
order: 4 | ||
--- | ||
|
||
# Native validation | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
```hbs template | ||
<div class='mx-auto max-w-md'> | ||
<ToucanForm | ||
class='space-y-4' | ||
@data={{this.data}} | ||
@onSubmit={{this.handleSubmit}} | ||
@validate={{validate-yup this.schema}} | ||
as |form| | ||
> | ||
<form.Input @label='Name' @name='name' /> | ||
<form.Input @label='Email' @name='email' /> | ||
<Button class='w-full' type='submit'>Submit</Button> | ||
</ToucanForm> | ||
</div> | ||
``` | ||
|
||
```js component | ||
import Component from '@glimmer/component'; | ||
import { object, string } from 'yup'; | ||
|
||
export default class extends Component { | ||
data = { | ||
name: '', | ||
email: '', | ||
}; | ||
|
||
schema = object({ | ||
name: string().required(), | ||
email: string().required().email(), | ||
}); | ||
|
||
handleSubmit(data) { | ||
console.log({ data }); | ||
|
||
alert( | ||
`Form submitted with:\n${Object.entries(data) | ||
.map(([key, value]) => `${key}: ${value}`) | ||
.join('\n')}` | ||
); | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
--- | ||
title: Yup validation | ||
order: 3 | ||
--- | ||
|
||
# Yup validation | ||
|
||
This demo shows how to implement [yup](https://github.com/jquense/yup) validation with ember-toucan-form, powered by [ember-headless-form](https://ember-headless-form.pages.dev/docs/validation/yup). | ||
|
||
## Install the adapter package | ||
|
||
Before using yup validations with Toucan Form, you'll need to install it as a dependency. | ||
|
||
```bash | ||
pnpm add yup ember-headless-form-yup | ||
# or | ||
yarn add yup ember-headless-form-yup | ||
# or | ||
npm install yup ember-headless-form-yup | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.