Forms: Sending Data

Learn how collect and send data in response to user actions in your components.

As an interface builder, Mason collects and sends data using form elements. Forms are, by default, submitted using the browser's fetch API. Using the Configure section of the Builder, you may set your form's action, method, and input fields to match the format expected by the server or API you'd like to send data to. Mason forms support the following encoding types:

  • application/json - (default) serializes the form fields as a JSON payload for any request method except for GET (form fields are url-encoded as query string parameters for GET requests)

  • application/x-www-form-urlencoded - the keys and values are encoded in key-value tuples separated by '&', with a '=' between the key and the value. Non-alphanumeric characters in both keys and values are percent encoded.

  • text/plain - serializes the form fields as a JSON payload for any request method except for GET. This should only be used for a server that expects an application/json payload but does not include application/json in its Accept-Headers list, or does not implement the OPTIONS pre-flight request.

Request Methods

Mason supports GET, POST, PUT, and DELETE HTTP request methods.

Input Types

Mason supports inputs of the following type:

  • checkbox

  • email

  • hidden

  • number

  • password

  • radio

  • tel

  • text

  • url

in addition to select elements, which may contain any value string.

Request Body

For requests with a body, form fields will be serialized with the keys matching the name attribute provided in the Mason Builder.

Consider the form below, with inputs named email, password, firstName, lastName

which will have the following payload when sent via POST

{
    email: 'john@appleseed.com',
    password: '12345678',
    firstName: 'John',
    lastName: 'Appleseed'
}

Composite Keys

Composite keys may be used to create nested payload structures.

Two inputs with the name attributes user[name][first] and user[name][last] will result in the following payload when encoded as application/json

{
    user: {
        name: {
            first: 'John',
            last: 'Appleseed'
        }
    }
}

Arrays may be created by using numeric indices or omitting the index altogether, such as names[] or names[0], names[1], names[2].

Validation

Mason will abort submission if any required fields are empty. To perform custom validation, use the willSendData callback (see below).

Callbacks

Mason components accept two callbacks for intercepting form submissions and server responses, willSendData and didReceiveData. You may provide these as props to your React components, or register them using the Mason global object (more on this below).

willSendData

This function is invoked prior to sending data to the form's action. It is invoked only if validation passes - meaning the user has filled out all required form fields with non-empty values.

render() {
    <Canvas id="YOUR_COMPONENT_ID" willSendData={(form, name, componentId) => {
        const { data: { password } } = form;
        if (password && password.length >= 8) {
            return form;
        }
        return false;
    }} />
}

willSendData will receive the following arguments:

  • form - an object containing the following structure

{
     action: 'https://example.com/submission?componentId=YOUR_COMPONENT_ID',
     data: {
         // ...serialized form data
     },
     headers: {
         'Content-Type': 'application/json' // encoding type you specified
     }
 }
    
  • name - the name of this form as provided in the Configure tab of the Builder, if specified; useful if you want to reuse the same callback across multiple forms

  • componentId - the id of the component, useful if you want to use the same callback across multiple components

You may mutate any parts of the form argument, but you should leave the top-level keys intact. Your callback may return one of the following two options:

  • false or a Promise that rejects to abort form submission

  • The form object, mutated or not, or a Promise that resolves with the form object

If you provide a willSendData callback, you must return one of these responses - if you want to submit the form data unmodified, simply return form at the end of your function. The value of data will be submitted to action with the headers.

didReceiveData

This function is invoked upon receiving a 2xx response code from a server in response to a form submission. It will receive the response body and the form name attribute as specified in the Configure section of the Builder.

render() {
    <Canvas id="YOUR_COMPONENT_ID" didReceiveData={(response, name) => {
        // do something with user
        const { user: { id } } = response;
    }} />
}

Using Forms to Trigger User Actions

While Mason supports click events on individual elements, in many cases actions you may not traditionally use a form for, say making a button or image clickable to perform an action for the user, are better achieved using a form. Even if you aren't going to send any data to a server, a form with a hidden input specifying the id of the action you want to perform and a submit button is an easy way to perform custom actions in response to user action in your Mason components. If you don't want to send any data, you may leave the form action blank, or return false from your willSendData callback.

Callbacks with HTML / Global Callbacks

If you're embedding your feature as HTML, you cannot pass functions as attributes. Instead, you may register callbacks using the Mason.callback function. This function allows you to register a callback without using props, and has the following signature:

Mason.callback(type, handler, [componentId])
<mason-canvas id="register" data-id="YOUR_COMPONENT_ID"></mason-canvas>

<script type="text/javascript">
    Mason.callback('willSendData', function(form, name, componentId) {
        // callback logic
        return form;
    });
</script>

You may specify an optional third argument, componentId to provide a scoped callback for a single component id. Omitting the componentId argument will cause your callback to be invoked for every event of the specified type. Un-scoped callbacks are a useful place to perform universal actions like providing auth credentials.

Mason.callback('willSendData', (form) => {
    return {
        ...form,
        headers: {
            Authorization: this.state.idToken,
        }
    };
});

Callbacks are invoked from most specific scope to least specific. If you provide three callbacks, one as a prop to a React component, one registered with the same componentId using Mason.callback and a third registered as an un-scoped callback, they will be invoked in the order: prop, scope registered, un-scoped registered. The response from each preceding callbacks will be the first argument into the next callback in the chain.

Last updated