/ Gists / 24 useForm
On gists

24 useForm

cdruc vue

useForm.js Raw #

import {reactive} from "vue";

export default function useForm(fields) {
  return reactive({
    fields,
    processing: false,
    error: null,
    async submit(submitter) {
      if (this.processing) return;

      this.error = null;
      this.processing = true;

      try {
        await submitter(this.fields);
      } catch (err) {
        this.error = err;
      }

      this.processing = false;
    },
  });
}

PostCreate.vue Raw #

<script setup>
import {ref} from "vue";
import axios from "@/lib/axios";
import useForm from "@/composables/form";
import {useRouter} from "vue-router";

const router = useRouter();

const form = useForm({
  title: "",
  content: "",
});
async function handleSubmit() {
  await form.submit(async fields => {
    await axios.post("/api/posts", fields);
    await router.push("/");
  });
}
</script>

<template>
  <main>
    <h1>Create post</h1>

    <p
      class="text-red-500"
      v-if="form.error?.message"
    >
      {{ form.error.message }}
    </p>

    <form
      class="space-y-2"
      @submit.prevent="handleSubmit"
    >
      <div class="flex flex-col">
        <label for="title">Title</label>
        <input
          type="text"
          v-model="form.fields.title"
          id="title"
        />
        <span
          class="text-red-500"
          v-if="form.error?.validation.title"
        >
          {{ form.error?.validation.title }}
        </span>
      </div>
      <div class="flex flex-col">
        <label for="content">Content</label>
        <textarea
          rows="4"
          v-model="form.fields.content"
          id="content"
        ></textarea>
        <span
          class="text-red-500"
          v-if="form.error?.validation.content"
        >
          {{ form.error?.validation.content }}
        </span>
      </div>
      <div>
        <button
          class="bg-blue-500 hover:bg-blue-600 px-3 py-1.5 rounded text-white"
        >
          {{ form.processing ? "Creating..." : "Create" }}
        </button>
      </div>
    </form>
  </main>
</template>