-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
011adb5
commit d19d63c
Showing
9 changed files
with
1,009 additions
and
1 deletion.
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
74 changes: 74 additions & 0 deletions
74
src/pages/[platform]/build-ui/formbuilder/call-to-action/index.mdx
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,74 @@ | ||
import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; | ||
|
||
export const meta = { | ||
title: 'Customize action buttons (Submit, Cancel, Clear, Reset)', | ||
description: 'Amplify Studio generated forms come with three action buttons: **Submit**, **Cancel**, and **Clear** or **Reset**, depending on whether the form creates or updates a record.', | ||
platforms: [ | ||
'javascript', | ||
'react', | ||
'nextjs' | ||
], | ||
canonicalObjects: [ | ||
{ | ||
platforms: [ | ||
'javascript', | ||
'react', | ||
'nextjs' | ||
], | ||
canonicalPath: '/gen1/javascript/build-ui/formbuilder/call-to-action/' | ||
} | ||
] | ||
}; | ||
|
||
export const getStaticPaths = async () => { | ||
return getCustomStaticPath(meta.platforms); | ||
}; | ||
|
||
export function getStaticProps(context) { | ||
return { | ||
props: { | ||
platform: context.params.platform, | ||
meta | ||
} | ||
}; | ||
} | ||
|
||
Amplify Studio generated forms come with three action buttons: **Submit**, **Cancel**, and **Clear** or **Reset**, depending on whether the form creates or updates a record. | ||
|
||
## Change button positions | ||
|
||
You can choose to show the action buttons on the bottom (default), top, or top and bottom of the form. | ||
|
||
1. From [Amplify Studio](/gen1/[platform]/tools/console/adminui/start/#logging-in-and-creating-an-app): Select the action buttons | ||
2. Go to **Display** > **Position** | ||
3. Select **Bottom**, **Top**, or **Top & bottom** | ||
|
||
<video autoPlay={true} muted={true} loop={true} width="100%" playsInline={true}> | ||
<source src="/images/console/formbuilder/call-to-action-position.mp4" /> | ||
</video> | ||
|
||
## Customize label for Submit, Cancel, Clear, and Reset buttons | ||
|
||
You can customize action button labels to better describe your form's use case, such as changing `Submit` to `Create note`. | ||
|
||
1. From [Amplify Studio](/gen1/[platform]/tools/console/adminui/start/#logging-in-and-creating-an-app): Select the action buttons | ||
2. Go to **Display** > **Submit button label** | ||
3. Enter your custom button label | ||
|
||
<video autoPlay={true} muted={true} loop={true} width="100%" playsInline={true}> | ||
<source src="/images/console/formbuilder/call-to-action-label.mp4" /> | ||
</video> | ||
|
||
## Toggle visibility for Submit, Cancel, Clear, and Reset buttons | ||
|
||
You can customize the visibility of action buttons to better accommodate your form's use case. For example, if you show the form in a modal with an `X` as a close button, you can hide the redundant `Cancel` action button. | ||
|
||
1. From [Amplify Studio](/gen1/[platform]/tools/console/adminui/start/#logging-in-and-creating-an-app): Select the action buttons | ||
2. Go to **Display** > **Submit button is visible** | ||
3. Enter your custom button label | ||
|
||
<video autoPlay={true} muted={true} loop={true} width="100%" playsInline={true}> | ||
<source src="/images/console/formbuilder/call-to-action-visibility.mp4" /> | ||
</video> | ||
|
||
If you hide all form action buttons, you can still leverage the [`onChange` event handler](/gen1/[platform]/build-ui/formbuilder/lifecycle/#get-form-data-as-your-user-inputs-data---onchange) to self-manage the form lifecycle. This is useful for a form that updates data in real-time without explicit user confirmation. |
170 changes: 170 additions & 0 deletions
170
src/pages/[platform]/build-ui/formbuilder/customize/index.mdx
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,170 @@ | ||
import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; | ||
|
||
export const meta = { | ||
title: 'Customize form inputs', | ||
description: 'Use the Form Builder in Amplify Studio to customize React form components. You can add new form inputs, bind them to a field, customize labels, and add validation rules.', | ||
platforms: [ | ||
'javascript', | ||
'react', | ||
'nextjs' | ||
], | ||
canonicalObjects: [ | ||
{ | ||
platforms: [ | ||
'javascript', | ||
'react', | ||
'nextjs' | ||
], | ||
canonicalPath: '/gen1/javascript/build-ui/formbuilder/customize/' | ||
} | ||
] | ||
}; | ||
|
||
export const getStaticPaths = async () => { | ||
return getCustomStaticPath(meta.platforms); | ||
}; | ||
|
||
export function getStaticProps(context) { | ||
return { | ||
props: { | ||
platform: context.params.platform, | ||
meta | ||
} | ||
}; | ||
} | ||
|
||
In Gen 2, you own updating the code directly for the generated form. Here's how you can customize the form. | ||
|
||
## Manually add form input field | ||
|
||
You can manually add a form input connected to a data model to the generated form. For example, let's say you add a `priority` field to your data model. Make the following edits: | ||
|
||
```jsx title="src/ui-components/TodoCreateForm.js" | ||
// 1. Set initialValues | ||
const initialValues = { | ||
content: "", | ||
// highlight-next-line | ||
priority: "" // Initial value for priority | ||
}; | ||
|
||
// 2. State setup | ||
const [priority, setPriority] = React.useState(initialValues.priority); | ||
|
||
// 3. Update resetValues | ||
const resetStateValues = () => { | ||
.. // previous fields | ||
// highlight-next-line | ||
setPriority(initialValues.priority) | ||
setErrors({}); | ||
}; | ||
|
||
// 4. Validation setup | ||
const validations = { | ||
content: [], | ||
// highlight-next-line | ||
priority: [] // Assuming no special validations for now | ||
}; | ||
|
||
// 5. Update form submission | ||
onSubmit={async (event) => { | ||
event.preventDefault(); | ||
let modelFields = { | ||
.., | ||
// highlight-next-line | ||
priority | ||
}; | ||
|
||
// 6. Add TextField | ||
<TextField | ||
label="Priority" | ||
isRequired={false} | ||
isReadOnly={false} | ||
value={priority} | ||
onChange={(e) => { | ||
let { value } = e.target; | ||
if (onChange) { | ||
const modelFields = { | ||
priority: value, | ||
}; | ||
const result = onChange(modelFields); | ||
value = result?.priority ?? value; | ||
} | ||
if (errors.priority?.hasError) { | ||
runValidationTasks("priority", value); | ||
} | ||
setPriority(value); | ||
}} | ||
onBlur={() => runValidationTasks("priority", priority)} | ||
errorMessage={errors.priority?.errorMessage} | ||
hasError={errors.priority?.hasError} | ||
{...getOverrideProps(overrides, "priority")} | ||
/> | ||
|
||
``` | ||
## Manually add option fields | ||
[Select Fields](https://ui.docs.amplify.aws/react/components/selectfield), [Radio Group Fields](https://ui.docs.amplify.aws/react/components/radiogroupfield), and [Autocomplete Fields](https://ui.docs.amplify.aws/react/components/autocomplete) require a set of options for your users to choose from. For example, a "Status" input can only have the options "Not started", "In progress", and "Done". This would be identical to the above 6 steps, but in step 6 you would replace `<TextField>` with `<SelectField>` | ||
```js title="src/ui-components/TodoCreateForm.js" | ||
// 6. Import <SelectField> component and add to form return | ||
<SelectField | ||
label="Label" | ||
placeholder="Please select an option" | ||
value={status} | ||
onChange={(e) => { | ||
let { value } = e.target; | ||
if (onChange) { | ||
const modelFields = { | ||
status: value | ||
}; | ||
const result = onChange(modelFields); | ||
value = result?.status ?? value; | ||
} | ||
if (errors.status?.hasError) { | ||
runValidationTasks("status", value); | ||
} | ||
setStatus(value); | ||
}} | ||
onBlur={() => runValidationTasks("status", status)} | ||
errorMessage={errors.status?.errorMessage} | ||
hasError={errors.status?.hasError} | ||
{...getOverrideProps(overrides, "status")} | ||
> | ||
<option children="Not started" value="Not started" {...getOverrideProps(overrides, "statusoption0")}></option> | ||
<option children="In progress" value="In progress" {...getOverrideProps(overrides, "statusoption1")}></option> | ||
<option children="Done" value="Done" {...getOverrideProps(overrides, "statusoption2")}></option> | ||
</SelectField> | ||
``` | ||
## Configure form spacings (paddings and gaps) | ||
Add spacing to your form and between inputs. Spacing values can either be a CSS length value (`px`, `rem`, `em`, `%`) or a reference to your theme object's spacing value (`xss`, `medium`, `large`). | ||
```js title="src/ui-components/TodoCreateForm.js" | ||
... | ||
return ( | ||
<Grid | ||
as="form" | ||
// highlight-start | ||
rowGap="15px" //edit horizontal gap | ||
columnGap="15px" //edit vertical gap | ||
padding="20px" // edit pading around the form inputs and border | ||
// highlight-end | ||
... | ||
``` | ||
## Enable list inputs | ||
`TextInput`s can accept multiple values. This functionality is only enabled for inputs not linked to a data model. If your input is linked to an existing model, this feature is controlled directly on the model by toggling the "Is array" property on the corresponding field. Here is what a list input looks like for the end user: | ||
<video autoPlay={true} muted={true} loop={true} width="100%" playsInline={true}> | ||
<source src="/images/console/formbuilder/customize-list-control.mp4" /> | ||
</video> | ||
```js title="src/ui-components/TodoCreateForm.js" | ||
// @Danny Banks TODO | ||
|
||
``` |
117 changes: 117 additions & 0 deletions
117
src/pages/[platform]/build-ui/formbuilder/data-binding/index.mdx
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,117 @@ | ||
import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; | ||
|
||
export const meta = { | ||
title: 'Data binding', | ||
description: 'Cloud connected forms can be bound to data models with relationships, allowing multiple data models to be updated upon submission.', | ||
platforms: [ | ||
'javascript', | ||
'react', | ||
'nextjs' | ||
], | ||
canonicalObjects: [ | ||
{ | ||
platforms: [ | ||
'javascript', | ||
'react', | ||
'nextjs' | ||
], | ||
canonicalPath: '/gen1/javascript/build-ui/formbuilder/data-binding/' | ||
} | ||
] | ||
}; | ||
|
||
export const getStaticPaths = async () => { | ||
return getCustomStaticPath(meta.platforms); | ||
}; | ||
|
||
export function getStaticProps(context) { | ||
return { | ||
props: { | ||
platform: context.params.platform, | ||
meta | ||
} | ||
}; | ||
} | ||
|
||
## Connected forms | ||
|
||
Connected Forms are bound to a model in your app's [data schema](/gen1/[platform]/tools/console/data/data-model/). Whenever a connected form is submitted, a record is automatically created or updated in the bound data model, with some or all of the form's input fields mapping to fields in the data model. | ||
|
||
Connected forms automatically work with any Amplify GraphQL API , [with or without DataStore](/gen1/[platform]/tools/console/data/data-model/#datastore-and-graphql), and no `onSubmit` handling is required. | ||
|
||
## Unconnected forms | ||
|
||
Unconnected Forms are standalone React components that can be used in any React or Nextjs project, even without an AWS account. Upon submission, the input values for the form are [accessible via the `onSubmit` hook for handling](/gen1/[platform]/build-ui/formbuilder/lifecycle/#handle-form-data-submissions---onsubmit). | ||
|
||
You can build unconnected forms without ever logging into AWS [using the Amplify Sandbox](https://sandbox.amplifyapp.com/ui-library). | ||
|
||
## Types of forms | ||
|
||
All connected and unconnected forms are either a **Create** form or an **Update** form. | ||
|
||
### Create forms | ||
|
||
Create forms render a form with empty inputs. If a create form is connected to a data model, will always generate a new record upon submission. | ||
|
||
### Update forms | ||
|
||
Update forms expect an input value in order to pre-populate the form. | ||
|
||
For update forms that are connected to a data model, you can use the `id` prop, or the model prop: | ||
|
||
- `id` prop: id string of the record you want to update. For example: | ||
|
||
```jsx | ||
<AuthorUpdateForm id="ac74af5c-3aab-4274-8f41-23e1e6576af5" /> | ||
``` | ||
|
||
- Model prop: if your form is bound to a data model named `Author`, your form will have a prop named `author` as well, which can receive a record. For example: | ||
|
||
```jsx | ||
|
||
<AuthorUpdateForm author={authorRecord}> | ||
|
||
``` | ||
|
||
It is generally recommended to use the model prop instead of the `id` prop. | ||
|
||
For unconnected update forms, you can pass an object to the `initialData` prop to pre-populate the form. However, as with all unconnected forms, you must handle the form submission in code. | ||
|
||
## Customizing data binding | ||
|
||
### Bind an unconnected form to a data model | ||
|
||
If you want to convert an unconnected form to a connected form, you can do so from within the form configuration menu. To configure your form's data model mapping: | ||
|
||
1. [Log into Amplify Studio](/gen1/[platform]/tools/console/adminui/start/) and select the **UI Library** from the left-hand navigation bar | ||
1. Select your unconnected form and select **Configure** in the upper right-hand corner | ||
1. In the upper right-hand corner, use the **Data model mapping** dropdown menu to update your form | ||
|
||
![Data model mapping drop down with options for an unconnected form](/images/console/formbuilder/data-model-mapping.png) | ||
|
||
From this dropdown menu, you have several options: | ||
|
||
**Create new data model**: Studio will use your form to [generate a brand-new data model in your schema](/gen1/[platform]/tools/console/data/data-model/) | ||
|
||
**Select from an existing model**: | ||
|
||
- If your form matches the data model, Studio will bind them together, converting your unconnected form to a connected form | ||
- If your form doesn't match the data model, Studio will add fields to match to your form (or schema) to ensure a match | ||
|
||
**Map data in code**: Use this option to ignore data mapping, and keep this form unconnected | ||
|
||
### Extend a connected form | ||
|
||
If your form is already connected to a data model, Studio will help you manage your connection as you extend your form. To extend a connected form: | ||
|
||
1. [Log into Amplify Studio](/gen1/[platform]/tools/console/adminui/start/) and select the **UI Library** from the left-hand navigation bar | ||
1. Select your connected form and select **Configure** in the upper right-hand corner | ||
1. Add a new field of any kind | ||
|
||
Studio will list any fields that aren't mapped to your data model on the right-hand side. | ||
|
||
![Unmapped field appears in the right hand bar for the user to handle](/images/console/formbuilder/data-model-field-mapping.png) | ||
|
||
If you select **Update data model**, Studio will automatically add a field to your data model schema. | ||
|
||
If you select **I'll handle in code**, Studio will ignore the data mapping for this field, and you can handle this field using the `onSubmit` hook. |
Oops, something went wrong.