SyntaxStudy
Sign Up
Vue.js POST, PUT, DELETE and Form Submission
Vue.js Beginner 1 min read

POST, PUT, DELETE and Form Submission

Beyond GET requests, Vue components frequently need to create, update, and delete resources. The pattern is consistent: bind form fields with `v-model`, collect state in reactive refs, and dispatch the mutation inside an async handler attached to the form's `@submit.prevent` event. After a successful mutation, either update the local reactive state to reflect the change without a full refetch, or trigger a targeted refetch of the affected resource. Optimistic UI — immediately updating local state before the server confirms — creates a snappy user experience. If the server returns an error, roll back the optimistic update and surface the error message. Keep the original value in a temporary variable before mutating so the rollback is straightforward. Always disable form submission buttons while a request is in flight (`isSubmitting` ref) to prevent duplicate submissions. Validate inputs client-side first to catch obvious errors before hitting the network. Libraries like VeeValidate or Zod integrate seamlessly with the Composition API for schema-based form validation.
Example
<template>
  <form @submit.prevent="submitPost">
    <input v-model="form.title"   placeholder="Title"   required />
    <textarea v-model="form.body" placeholder="Body"    required></textarea>
    <p v-if="formError" class="error">{{ formError }}</p>
    <button type="submit" :disabled="isSubmitting">
      {{ isSubmitting ? 'Saving…' : 'Save Post' }}
    </button>
  </form>

  <button @click="deletePost(selectedId)" :disabled="isDeleting">
    {{ isDeleting ? 'Deleting…' : 'Delete' }}
  </button>
</template>

<script setup>
import { ref }    from 'vue';
import { useRouter } from 'vue-router';
import api        from '@/lib/axios';

const router      = useRouter();
const isSubmitting = ref(false);
const isDeleting   = ref(false);
const formError    = ref(null);
const selectedId   = ref(1);

const form = ref({ title: '', body: '' });

async function submitPost() {
  isSubmitting.value = true;
  formError.value    = null;
  try {
    const { data } = await api.post('/posts', { ...form.value, userId: 1 });
    router.push({ name: 'post-detail', params: { id: data.id } });
  } catch (e) {
    formError.value = e.response?.data?.message ?? e.message;
  } finally {
    isSubmitting.value = false;
  }
}

async function deletePost(id) {
  if (!confirm('Delete this post?')) return;
  isDeleting.value = true;
  try {
    await api.delete(`/posts/${id}`);
    router.push({ name: 'posts' });
  } finally {
    isDeleting.value = false;
  }
}
</script>

This is the last lesson in this section.

Create a free account to earn a certificate