Veevalidate验证select控件的问题

2020-04-14  本文已影响0人  奇松_ca45

vue本身没有form验证框架,veevalidate是比较流行的验证框架,使用上也很方便。我在实际使用过程中碰到一个问题,就是select控件的验证和input控件有所区别。我的form里有姓名输入框和所在省选择控件,都是必填项。表单打开时,显示如下:

这个表单是用veevalidate和bootstrapvue实现的。每个输入控件获得焦点后,如果没有输入任何东西将提示出错信息如下:

注意到state控件没有相同的行为,尽管代码是一样的。原因是Bootstrapvue没有在select上监听click和onblur实际。解决的办法如下:

template

Script,就是注册onblur事件,在事件处理函数里把状态进行修改和验证

完整的代码如下:

<template>

<ValidationObserver

    :ref="`contactForm${formId}`"

    v-slot="{invalid }"

    tag="form"

    class="w-100 bg-main-gray px-3"

    @submit.prevent="submit"

  >

<div class="row">

<div class="col-12 col-lg-6">

<label

          :for="`${formId}-name`"

          class="mt-3"

        >

<span class="text-danger">

*

</span>

Name

</label>

<ValidationProvider

          v-slot="{errors,touched,failed }"

          name="Name"

          :rules="{

regex:/^[\sa-zA-Z0-9()@&\-,.#]*$/,

required:true,

minMaxLength: [4,200]

}"

        >

<b-form-input

            :id="`${formId}-name`"

            v-model="data.name"

            autofocus

            tabindex="0"

            :state="touched ? !failed :null"

            maxlength="200"

            type="text"

          />

<div class="w-100 text-danger">

{{errors[0] }}

</div>

</ValidationProvider>

</div>

<div class="col-12 col-lg-6">

<label

          :for="`${formId}-address`"

          class="mt-3"

        >

<span class="text-danger">

*

</span>

Address

</label>

<ValidationProvider

          v-slot="{errors,touched,failed }"

          name="Address"

          :rules="{

regex:/^[\sa-zA-Z0-9()&\-,.#@]*$/,

required:true,

minMaxLength: [3,100]

}"

        >

<b-form-input

            :id="`${formId}-address`"

            v-model="data.address"

            :state="touched ? !failed :null"

            maxlength="100"

            tabindex="0"

          />

<div class="w-100 text-danger">

{{errors[0] }}

</div>

</ValidationProvider>

</div>

</div>

<div class="row">

<div class="col-12 col-lg-6">

<div class="row">

<div class="col-6">

<label

              :for="`${formId}-city`"

              class="mt-3"

            >

<span class="text-danger">

*

</span>

City

</label>

<ValidationProvider

              v-slot="{errors,touched,failed }"

              name="City"

              :rules="{

regex:/^[\sa-zA-Z0-9()&amp;]*$/,

required:true,

minMaxLength: [2,50]

}"

            >

<b-form-input

                :id="`${formId}-city`"

                v-model="data.city"

                tabindex="0"

                :state="touched ? !failed :null"

                type="text"

                maxlength="50"

              />

<div class="w-100 text-danger">

{{errors[0] }}

</div>

</ValidationProvider>

</div>

<div class="col-6">

<label

              :for="`${formId}-state`"

              class="mt-3"

            >

<span class="text-danger">

*

</span>

State

</label>

<ValidationProvider

              v-slot="{errors,touched }"

              name="State"

              :rules="{required:true }"

            >

<b-form-select

                :id="`${formId}-state`"

                v-model="data.state"

                :state="touched ? !isBlank(data.state) :null"

                :options="states"

                text-field="name"

                value-field="abbreviation"

                :required="true"

                tabindex="0"

              />

<div class="w-100 text-danger">

{{errors[0] }}

</div>

</ValidationProvider>

</div>

</div>

</div>

<div class="col-12 col-lg-6">

<div class="form-col">

<label

            :for="`${formId}-zip`"

            class="mt-3"

          >

<span class="text-danger">

*

</span>

ZIP

</label>

<ValidationProvider

            v-slot="{errors,touched,failed }"

            name="ZIP"

            :rules="{

zip:/^((\d{5})(-(\d{4}))?)|(([A-Z]\d[A-Z])(\s?)(\d[A-Z]\d))$/,

required:true,

minMaxLength: [3,20]

}"

          >

<b-form-input

              :id="`${formId}-zip`"

              v-model="data.zip"

              :state="touched ? !failed :null"

              maxlength="20"

              tabindex="0"

            />

<div class="w-100 text-danger">

{{errors[0] }}

</div>

</ValidationProvider>

</div>

<div class="form-col state" />

</div>

</div>

<div class="row">

<div class="col-12 col-lg-6">

<label

          :for="`${formId}-email`"

          class="mt-3"

        >

<span class="text-danger">

*

</span>

Email Address

</label>

<ValidationProvider

          v-slot="{errors,touched,failed }"

          name="Email"

          :rules="{

email:true,

required:true,

minMaxLength: [7,200]

}"

        >

<b-form-input

            :id="`${formId}-email`"

            v-model="data.email"

            :state="touched ? !failed :null"

            type="text"

            maxlength="200"

            tabindex="0"

          />

<span class="w-100 text-danger">

{{errors[0] }}

</span>

</ValidationProvider>

</div>

<div class="col-12 col-lg-6">

<label

          :for="`${formId}-phone`"

          class="mt-3"

        >

<span class="text-danger">

*

</span>

Phone Number

</label>

<ValidationProvider

          v-slot="{errors,touched,failed }"

          name="Phone"

          :rules="{

phone:/^(([1-9]\d{9})|(\([1-9]\d{2}\) ?\d{3}-\d{4})|([1-9]\d{2}[-.]\d{3}[-.]\d{4}))$/,

required:true,

minMaxLength: [3,15]

}"

        >

<b-form-input

            :id="`${formId}-phone`"

            v-model="data.phone"

            :state="touched ? !failed :null"

            tabindex="0"

            maxlength="15"

          />

<span class="w-100 text-danger">

{{errors[0] }}

</span>

</ValidationProvider>

</div>

</div>

<div class="row">

<div class="col-12">

<label

          :for="`${formId}-comments`"

          class="mt-3"

        >

<span class="text-danger">

*

</span>

Message

</label>

<ValidationProvider

          v-slot="{errors,touched,failed }"

          name="Comments"

          :rules="{required:true,minMaxLength: [2,500] }"

        >

<b-form-textarea

            :id="`${formId}-comments`"

            v-model="data.comments"

            :state="touched ? !failed :null"

            rows="4"

            maxlength="500"

            tabindex="0"

          />

<span class="w-100 text-danger">

{{errors[0] }}

</span>

</ValidationProvider>

</div>

</div>

<div class="row my-3">

<div class="col-12 d-flex justify-content-between">

<div

          v-if="allowAttachment"

          class="d-flex flex-nowrap align-items-center flex-grow-1"

        >

<span class="mb-0">

Attachments:

</span>

<b-form-file

            :id="`${formId}-attachment`"

            v-model="data.attachment"

            accept=".jpeg, .jpg, .png, .pdf"

            placeholder="Choose file"

            browse-text=""

          />

</div>

<span v-else />

<BButton

          variant="primary"

          :disabled="invalid"

          class="d-flex flex-nowrap ml-1"

          @click="submit"

          @keypress.enter="submit"

        >

Send

<b-img

            v-if="sending"

            class="ml-2"

            width="15px"

            alt="loading img"

            :src="loadingGifUrl"

          />

</BButton>

</div>

</div>

<b-toast

      :id="`success-toast-${formId}`"

      variant="success"

      solid

    >

<template v-slot:toast-title>

<div class="d-flex flex-grow-1 align-items-baseline">

Thank you for your feedback!

</div>

</template>

</b-toast>

</ValidationObserver>

</template>

<script>

import {ValidationProvider,extend,ValidationObserver }from 'vee-validate';

import {required,email,regex }from 'vee-validate/dist/rules';

import {

BButton,

BFormFile,

BFormInput,

BImg,

BFormSelect,

BFormTextarea

}from 'bootstrap-vue';

import Vuefrom 'vue';

import axios from 'axios';

import {isBlank }from '@/main/ui/js/util/utils';

import loadingGifUrlfrom '@/main/ui/components/images/loadingImg';

import {EventBus }from '@/main/ui/js/event-bus';

extend('required', {

...required,

message:'{_field_} is required'

});

extend('regex', {

...regex,

message:'{_field_} can not contain special characters'

});

extend('zip', {

...regex,

message:'Invalid Zip Code'

});

extend('phone', {

...regex,

message:'Invalid phone number'

});

extend('email', {

...email,

message:'Invalid email address'

});

extend('minMaxLength', {

validate (value, { min, max }) {

return value.length >= min && value.length <= max;

},

params: ['min','max'],

message:'{_field_} needs to be between {min} and {max} characters long'

});

let validation = BFormSelect.extend({

mounted () {

let _this =this;

this.$el.onblur = () => {

_this.$parent.flags.touched =true;

_this.$parent.validate();

};

}

});

let ValidateSelect = BFormSelect.extend(validation);

export default {

name:'ContactForm',

components: {

BFormFile,

BButton,

BImg,

BFormInput,

BFormTextarea,

'b-form-select':ValidateSelect,

ValidationProvider,

ValidationObserver

  },

props: {

allowAttachment: {

type:Boolean,

default:false

    },

data: {

type:Object,

required:true,

default:function () {

return {};

}

},

paramName: {

type:String,

required:true

    },

url: {

type:String,

required:true

    },

propertyId: {

type:String,

default:null

    }

},

data:function () {

return {

loadingGifUrl: loadingGifUrl,

states: [{name:'- none -',abbreviation:'' }, ...window.states],

sending:false,

formId:this.paramName

    };

},

methods: {

submit () {

if (this.sending) {

// prevent double submit

        return;

}

let vm =this;

this.sending =true;

let form = { ...this.data };

let data =new FormData();

data.append('attachment',form.attachment);

form.attachment =undefined;

data.append(this.paramName,JSON.stringify(form));

if (this.propertyId) {

data.append('property.id',this.propertyId);

}

function resetForm () {

Vue.set(vm,'data', {

name:'',

address:'',

phone:'',

email:'',

city:'',

state:'',

zip:'',

comments:'',

attachment:null

        });

vm.$refs[`contactForm${vm.formId}`].reset();

EventBus.$emit('resetForm',vm.paramName);

}

axios

        .post(`${window.baseURL}${this.url}`,data, {

headers: {

'Content-Type':'multipart/form-data'

          }

})

.then(function () {

vm.sending =false;

vm.$bvToast.show(`success-toast-${vm.formId}`);

resetForm();

})

.catch(function (reply) {

vm.sending =false;

vm.$bvModal.msgBoxOk(reply.response.data.message, {

title:'Unknown Server Error Occurred',

size:'sm',

buttonSize:'sm',

okVariant:'danger',

headerClass:'p-2 border-bottom-0',

footerClass:'p-2 border-top-0',

centered:true

          });

});

},

isBlank:isBlank

  }

};

</script>

上一篇 下一篇

猜你喜欢

热点阅读