Dynamic Fields

Field configurations can be dynamic, based on previously entered data. Here are a few examples:

<Form
    config={{
        fields: (data) => {
            return [
                {
                    id: "field1",
                    label: "Field 1",
                    type: "text"
                },
                {
                    id: "field2",
                    label: "Field 2",
                    secondaryText: "This field is only required if Field 1 is populated. Add something to the first field to see this field getting required.",
                    type: "text",
                    isRequired: data.field1
                },
                {
                    id: "field3",
                    label: "Field 3",
                    type: "text"
                },
                {
                    id: "field4",
                    label: "Field 4",
                    secondaryText: "This field is only enabled if Field 3 is populated.",
                    type: "text",
                    isDisabled: !data.field3
                },
                {
                    id: "name",
                    label: "Name",
                    type: "text",
                    isRequired: true
                },
                {
                    id: "age",
                    label: data.name ? `What is the age of ${data.name}?` : "Age",
                    secondaryText: "The label of this field is dynamic.",
                    type: "number"
                }
            ]
        }
    }}
    ...
/>

You can do the same in the render function, for example if you want to hide a group of fields if a checkbox above isn't checked:

<Form
    render={({ fieldProps }) => (
        <div>
            {fieldProps.fields.myCheckbox}
            <br />
            {fieldProps.data.myCheckbox ? (
                <div>
                    {fieldProps.fields.groupField1}
                    <br />
                    {fieldProps.fields.groupField2}
                    ...
                </div>
            ) : null}
        </div>
    )}
    ...
/>

However, be careful to not make a form to dynamic, this can be irritating for the user and hard to test.

Related Demo

Function Props

For even more dynamicness, Stages has now support for function props. Basically you can turn any configuration property into a function property by adding Fn to it. For example you can turn the property label into a function property by naming it labelFn. This works for all non reserved props. Here's an example:

{
    id: "email",
    labelFn: ({ fieldData }) => {
        if (fieldData && fieldData.indexOf('@') > -1 && fieldData.indexOf('.') > -1) {
            return "Email 😎";
        }
        if (fieldData && (fieldData.indexOf('@') === -1 || fieldData.indexOf('.') === -1)) {
            return "Email 🤕";
        }
        return "Email";
    },
    type: "email",
    isRequired: true
}

What we do here is render a different emoticon in the label based on the validity of the entered email.

In all function props, you have access to the following data:

  • path: The fields path
  • fieldData: The current field data
  • alldata: All the forms data
  • interfaceState: The forms interface state

Related Demo

The isRendered prop

To help with dynamic fields, we've added the isRendered property. An example:

...
{
    id: "myfield",
    label: "My Field",
    type: "text",
    isRendered: (path, data, allData) => {
        if (path.includes("[1]")) return false;
        return true;
    }
},
...

This field only renders, if it's in a collection and has an index of 1, so in other words, if it is the second item in a collection. All other items in the collection will not render this field.