Refactoring to Inertia Forms

Published on Apr 23, 2021 by Yaz Jallad

Here at Aryeo, we've been fully invested in building new features and refactoring previously built sections of our app using Vue 3 and Inertia.

Since we opted to go this route early on in the development of Inertia, we originally had to approach handling form data manually. For each form, we had to create an object manually that managed local state of user inputs and would eventually be sent to the server ourselves.

With the launch of the Inertia Vue 3 0.3.0 release, however, the boilerplate required to create forms was drastically reduced.
This is thanks to Inertia's new form helper.

Our Approach Before Inertia Vue 3 0.3.0 Release

Here is an example of how we typically approached our forms.

** Note extra elements have been removed to focus on the actual code. **

<template>
  <form @submit.prevent="submit">
    <input v-mode="form.email" name="email" type="email" />
    <input v-model="form.password" name="password" type="password" />
    <input type="checkbox" name="remember" v-model="form.remember" />
    <button type="submit" :disabled="busy">Sign in</button>
  </form>
</template>

<script>
import { Inertia } from '@inertiajs/inertia'
import { ref, reactive } from '@vue/reactivity'

import Layout from '@Layouts/AuthLayout'

export default {
  layout: Layout,

  setup() {
    const busy = ref(false)

    const form = reactive({
      email: null,
      password: null,
      remember: false
    })

    const submit = () => {
      Inertia.post(route('auth.login'), form, {
        preserveScroll: true,
        onStart: () => (busy.value = true),
        onFinish: () => (busy.value = false)
      })
    }

    return {
      busy,
      form,
      submit
    }
  }
}
</script>

At first look, this form seems very straight forward. Let's step through some of the key elements:

  • In the setup method, we are declaring a busy variable, allow us to apply a disabled attribute to the form's submit button when the form request is being handled.
  • Next, we are creating the reactive form object with the starting values of the form state.
  • Next, we define the submit handler for the form; this is where we handle submitting the form to our backend using Inertia. We leverage the request lifecycle hooks to set the busy state of our form:
    • When the form starts its submission, we set that value to true
    • When it's complete, we set it to false.
      We also pass in the actual form object to this request as the request body.

There is nothing wrong with our above code at all; it works and it's very readable!

Updating This Form, Utilizing the Inertia Form Helper

With the new Inertia forms, we can remove much of this boilerplate. Let's take a look at how we can refactor this now:

<template>
  <form @submit.prevent="submit">
    <input v-mode="form.email" name="email" type="email" />
    <input v-model="form.password" name="password" type="password" />
    <input type="checkbox" name="remember" v-model="form.remember" />
    <button type="submit" :disabled="form.processing">Sign in</button>
  </form>
</template>

<script>
import { Inertia } from '@inertiajs/inertia'

import Layout from '@Layouts/AuthLayout'

export default {
  layout: Layout,

  setup() {
    const form = Inertia.form({
      email: null,
      password: null,
      remember: false
    })

    const submit = () => {
      form.post(route('auth.login'))
    }

    return {
      form,
      submit
    }
  }
}
</script>

Let's walk through our previous approach to form, how we were able to simplify our form by leveraging the Inertia form helped:

  • First, we no longer need a busy state flag, as the Inertia form object provides this out of the box. During the life of the request, the form object will update it's form.processing value for us. Therefore, we can utilize this attribute to manage the disabled state of our submit button: :disabled="form.processing".
  • Next, we don't have to create a reactive form object because the form call returns that for us.
  • Lastly, the form can submit itself by calling the method verb and passing our target URL as the first parameter (note: we're using Laravel to power our backend, meaning were able to leverage the Ziggy a global route() function).

Wrap

Using the Inertia form helper, the boilerplate code required to build a simple form is significantly reduced.