Search code examples
vue.jsyupvee-validate

VeeValidate with Yup: input type="number" value is converted to string on submit


I use VeeValidate and Yup for form validation and don't know why my input field with type="number" is converted to string on submit.

When I input 78 and submit the form the output of the console.log in the onSubmit(values) function is the following:

values: {
   prioritaet: "78"
}

Am I doing something wrong here or is this the normal behavior of VeeValidate and Yup? I would like to have a number instead of a string after submit.

My code looks like this:

<template>
  <div class="container m-3">
    <div class="row bg-primary align-items-center py-2">
      <div class="col">
        <h3 class="text-light mb-0">Format {{ this.action }}</h3>
      </div>
      <div class="col-auto">
        <h5 class="text-light mb-0">{{ this.formatTitle }}</h5>
      </div>
    </div>

    <Form @submit="onSubmit" :validation-schema="formatSchema" v-slot="{ errors }" ref="formatForm">
      <div class="row mt-4">
        <div class="col">
          <h5>Formatdaten</h5>
        </div>
      </div>

      <div class="row mb-2">
        <div class="col-4">
          <label for="prioritaet-input">Priorität: </label>
        </div>
        <div class="col">
          <Field type="number" name="prioritaet" id="prioritaet-input" class="w-100" />
        </div>
      </div>

      <div class="row justify-content-end">
        <div class="col-auto me-auto">
          <button class="btn btn-outline-primary">Änderungen übernehmen</button>
        </div>
        <div class="col-auto">
          <button class="btn btn-outline-primary">Abbrechen</button>
        </div>
        <div class="col-auto">
          <button type="sumbit" class="btn btn-outline-primary">Speichern</button>
        </div>
      </div>
      
      <div class="row mt-4">
        <template v-if="Object.keys(errors).length">
          <span class="text-danger" v-for="(message, field) in errors" :key="field">{{ message }}</span>
        </template> 
      </div>
    </Form>

  </div>
</template>
<script>
import { Form, Field } from "vee-validate";
import deLocale from "../assets/yup-localization.js";
import * as Yup from "yup";
import { markRaw } from "vue";

import { mapActions, mapState } from "vuex";

Yup.setLocale(deLocale);

export default {
  name: "FormatBearbeitungsSchirm",
  props: ["material_id"],
  data() {
    let action = "neu";
    let formatTitle = "Format neu";

    let formatSchema = markRaw(Yup.object().shape({
      prioritaet: Yup.number().min(1).max(100).integer().label("Priorität"),
    }));

    return { formatSchema, action, formatTitle };
  },
  created() {

  },
  components: {
    Form,
    Field,
  },
  methods: {
    onSubmit(values) {
      console.log("values", values);
    },
  },
};
</script>


Solution

  • It looks like there is currently no support for specifying the .number modifier on the internal field model value of <Field>, so the emitted form values would always contain a string for number-type fields.

    One workaround is to convert the value in the template, updating <Form>'s values slot prop in <Field>'s update:modelValue event:

    <Form @submit="onSubmit" v-slot="{ values }">
      <Field                             👆
        type="number"
        name="prioritaet"      👇
        @update:modelValue="values.prioritaet = Number(values.prioritaet)"
      />
    
      <button>Submit</button>
    </Form>
    

    demo

    Another simple workaround is to convert the property inside onSubmit before using it:

    export default {
      onSubmit(values) {
        values.prioritaet = Number(values.prioritaet)
    
        // use values here...
      }
    }