npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@barbapapazes/vue-forms

v0.1.5

Published

Streamline form handling in Vue with a straightforward and expressive API.

Downloads

389

Readme

vue-forms

[!NOTE] If you find this project useful, please consider supporting my work via GitHub Sponsors! 💜

npm version npm downloads

Streamline form handling in Vue with a straightforward and expressive API. Eliminate boilerplate code and concentrate on your form logic.

Installation

# ✨ Auto-detect
npx npm install @barbapapazes/vue-forms

# npm
npm install @barbapapazes/vue-forms

# yarn
yarn add @barbapapazes/vue-forms

# pnpm
pnpm install @barbapapazes/vue-forms

Usage

This package draws heavy inspiration from the useForm feature of Inertia.js.

To begin, import the useForm composable to instantiate a new form.

import { useForm } from '@barbapapazes/vue-forms'

Fields

You need to supply an object with the initial values of the form fields. Access them through the data object to bind them to the form inputs.

<script setup lang="ts">
import { useForm } from '@barbapapazes/vue-forms'

const { data } = useForm({
  email: '',
  password: '',
})
</script>

<template>
  <form>
    <input v-model="data.email" type="email">
    <input v-model="data.password" type="password">
    <button type="submit">
      Submit
    </button>
  </form>
</template>

Alternatively, you can wrap useForm with a reactive function to bypass the necessity of destructuring the useForm object. Read more about Vue.js composable functions.

<script setup lang="ts">
import { useForm } from '@barbapapazes/vue-forms'
import { reactive } from 'vue'

const form = reactive(useForm({
  email: '',
  password: '',
}))
</script>

<template>
  <form>
    <input v-model="form.data.email" type="email">
    <input v-model="form.data.password" type="password">
    <button type="submit">
      Submit
    </button>
  </form>
</template>

Validation

This library assumes that validation occurs on the server-side.

However, since we cannot predict the structure of a returned validation error, employ the transformErrorResponse hook to convert the error response into a format that maps to the form fields' errors.

Should your server return an error resembling this:

{
  "data": {
    "email": ["The email field is required."],
    "password": ["The password field is required."]
  }
}

Transform it as follows:

post('/login', {
  transformErrorResponse: (error) => {
    return {
      email: error.data.email?.[0],
      password: error.data.password?.[0],
    }
  }
})

This transformation maps the error messages to the corresponding fields, enabling display within the form. Without this transformation, errors cannot be displayed.

<template>
  <form @submit.prevent="submit">
    <input v-model="data.email" type="email">
    <span v-if="errors.email">{{ errors.email }}</span>

    <input v-model="data.password" type="password">
    <span v-if="errors.password">{{ errors.password }}</span>

    <button type="submit">
      Submit
    </button>
  </form>
</template>

Submitting

Once completed, you can submit the form to the server using several methods: submit, post, put, patch, and delete. The submit method is versatile and handles any HTTP method.

const { post } = useForm({
  email: '',
  password: '',
})

post('/login') // Sends a POST request to '/login' with a payload of { email: '', password: '' }

The useForm exposes additional references and methods:

  • processing is set to true while the form is submitting and reverts to false upon completion of the request (whether successful or not). This can be utilized to disable the submit button during submission.
  • recentlySuccessful is set to true following a successful submission of the form and resets to false after a brief delay. You can adjust the delay using the recentlySuccessfulTimeout option.
  • clearErrors clears the errors object. Specific errors can be cleared by passing the field name as an argument. For instance, clearErrors('email', 'password') clears the errors for both the email and password fields.
  • setError assigns an error. Pass the field name and error message as setError('email', 'The email field is required.'), or provide a partial error object like setError({ email: 'The email field is required.' }).
  • reset restores the form to its initial state, clearing both the data and errors objects.
<script setup lang="ts">
import { useForm } from '@barbapapazes/vue-forms'
import { reactive } from 'vue'

const form = reactive(useForm({
  name: 'John Doe',
  email: '',
}))

interface CreateUserResponse {
  data: {
    name: string
    email: string
  }
}

interface CreateUserValidationError {
  data: {
    errors: {
      message: string
      name?: string
      email?: string[]
    }
  }
}

function submit() {
  form.post<CreateUserResponse, CreateUserValidationError>('/form', {
    transformErrorResponse(error) {
      return {
        name: error.data.errors.name,
        email: error.data.errors.email?.[0],
      }
    },
    onSuccess() {
      form.reset()
    },
  })
}
</script>

<template>
  <h1> Vue Forms Playground </h1>

  <p v-if="form.recentlySuccessful">
    Form submitted successfully!
  </p>

  <form @submit.prevent="submit">
    <label>
      Name:
      <input v-model="form.data.name">
      <p> {{ form.errors.name }} </p>
    </label>

    <label>
      Email:
      <input v-model="form.data.email">
      <p> {{ form.errors.email }} </p>
    </label>

    <button
      type="submit"
      :disabled="form.processing"
    >
      Submit
    </button>
  </form>
</template>

Internally, the useForm composable employs the ofetch package. You can apply similar options as those available in the ofetch function to each method (e.g., interceptors to manage the usage of the XSRF-TOKEN cookie with onRequest).

form.post('/login', {
  baseURL: 'https://api.example.com',
  headers: {
    'Content-Type': 'application/json',
  },
})

TypeScript

The useForm composable leverages the provided inputs to infer the types of the data and errors objects.

You may also define types for the response from the server in the event of a successful submission or an error.

const form = reactive(useForm({
  email: '',
  password: '',
}))

// Successful response
interface CreateUserResponse {
  data: {
    name: string
    email: string
  }
}

// Error response
interface CreateUserValidationError {
  data: {
    errors: {
      message: string
      name?: string
      email?: string[]
    }
  }
}

function submit() {
  form.post<CreateUserResponse, CreateUserValidationError>('/api/login', {
    // eslint-disable-next-line node/handle-callback-err
    transformErrorResponse(error) {
      // `error` is typed using the `CreateUserValidationError` interface
    },
    onSuccess(response) {
      // `response` is typed using the `CreateUserResponse` interface
    },
  })
}

Development

  • Clone this repository
  • Install latest LTS version of Node.js
  • Enable Corepack using corepack enable
  • Install dependencies using pnpm install

After the local development environment is configured, navigate to the ./playground directory to launch the development server.

cd playground
pnpm dev # Start the Vite development server and a server API.

The playground simulates the library in a real-world context. It's a Vue 3 application utilizing the library from the src directory. There's no need to pre-build the library; it connects directly with Hot Module Replacement (HMR).

License

Published under the MIT license.

Sponsors

I would like to thank the following sponsors for supporting my work:

Sponsors