Vuelidate form added
parent
5d4915c890
commit
29f82af241
|
@ -35,6 +35,8 @@
|
|||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"@vuelidate/core": "^2.0.0-alpha.14",
|
||||
"@vuelidate/validators": "^2.0.0-alpha.12",
|
||||
"axios": "^0.19.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"chart.js": "2.7.3",
|
||||
|
|
|
@ -749,6 +749,17 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Validation",
|
||||
"meta": ["validation"],
|
||||
"children": [
|
||||
{
|
||||
"name": "Vuelidate",
|
||||
"to": "/vuelidate",
|
||||
"badge": "New"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Misc",
|
||||
"meta": ["misc"],
|
||||
|
|
|
@ -815,6 +815,11 @@ const routes = [
|
|||
path: '/galleria/advanced',
|
||||
name: 'galleriaadvvanced',
|
||||
component: () => import('../views/galleria/GalleriaAdvancedDemo.vue')
|
||||
},
|
||||
{
|
||||
path: '/vuelidate',
|
||||
name: 'vuelidateform',
|
||||
component: () => import('../views/validation/VuelidateFormDemo.vue')
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -0,0 +1,563 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="content-section introduction">
|
||||
<div class="feature-intro">
|
||||
<h1>Vuelidate</h1>
|
||||
<p>PrimeVue components can be easily used/integrated with <a href="https://vuelidate.js.org/">Vuelidate</a>. In this example, a register panel is simulated using Vuelidate.</p>
|
||||
</div>
|
||||
<AppInputStyleSwitch />
|
||||
</div>
|
||||
|
||||
<div class="content-section implementation form-demo">
|
||||
<Dialog v-model:visible="showMessage" :breakpoints="{ '960px': '80vw' }" :style="{ width: '30vw' }" position="top">
|
||||
<div class="p-d-flex p-ai-center p-dir-col p-pt-6 p-px-3">
|
||||
<i class="pi pi-check-circle" :style="{fontSize: '5rem', color: 'var(--green-500)' }"></i>
|
||||
<h5>Registration Successful!</h5>
|
||||
<p :style="{lineHeight: 1.5, textIndent: '1rem'}">
|
||||
Your account is registered under name <b>{{name}}</b> ; it'll be valid next 30 days without activation. Please check <b>{{email}}</b> for activation instructions.
|
||||
</p>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="p-d-flex p-jc-center">
|
||||
<Button label="OK" @click="toggleDialog" class="p-button-text" />
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
|
||||
<div class="p-d-flex p-jc-center">
|
||||
<div class="card">
|
||||
<h5 class="p-text-center">Register</h5>
|
||||
<form @submit.prevent="handleSubmit(!v$.$invalid)" class="p-fluid">
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<InputText id="name" v-model="v$.name.$model" :class="{'p-invalid':v$.name.$invalid && submitted}" />
|
||||
<label for="name" :class="{'p-error':v$.name.$invalid && submitted}">Name*</label>
|
||||
</div>
|
||||
<small v-if="(v$.name.$invalid && submitted) || v$.name.$pending.$response" class="p-error">{{v$.name.required.$message.replace('Value', 'Name')}}</small>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label p-input-icon-right">
|
||||
<i class="pi pi-envelope" />
|
||||
<InputText id="email" v-model="v$.email.$model" :class="{'p-invalid':v$.email.$invalid && submitted}" aria-describedby="email-error"/>
|
||||
<label for="email" :class="{'p-error':v$.email.$invalid && submitted}">Email*</label>
|
||||
</div>
|
||||
<span v-if="v$.email.$error && submitted">
|
||||
<span id="email-error" v-for="(error, index) of v$.email.$errors" :key="index">
|
||||
<small class="p-error">{{error.$message}}</small>
|
||||
</span>
|
||||
</span>
|
||||
<small v-else-if="(v$.email.$invalid && submitted) || v$.email.$pending.$response" class="p-error">{{v$.email.required.$message.replace('Value', 'Email')}}</small>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<Password id="password" v-model="v$.password.$model" :class="{'p-invalid':v$.password.$invalid && submitted}" toggleMask>
|
||||
<template #header>
|
||||
<h6>Pick a password</h6>
|
||||
</template>
|
||||
<template #footer="sp">
|
||||
{{sp.level}}
|
||||
<Divider />
|
||||
<p class="p-mt-2">Suggestions</p>
|
||||
<ul class="p-pl-2 p-ml-2 p-mt-0" style="line-height: 1.5">
|
||||
<li>At least one lowercase</li>
|
||||
<li>At least one uppercase</li>
|
||||
<li>At least one numeric</li>
|
||||
<li>Minimum 8 characters</li>
|
||||
</ul>
|
||||
</template>
|
||||
</Password>
|
||||
<label for="password" :class="{'p-error':v$.password.$invalid && submitted}">Password*</label>
|
||||
</div>
|
||||
<small v-if="(v$.password.$invalid && submitted) || v$.password.$pending.$response" class="p-error">{{v$.password.required.$message.replace('Value', 'Password')}}</small>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<Calendar id="date" v-model="date" :showIcon="true" />
|
||||
<label for="date">Birthday</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<Dropdown id="country" v-model="country" :options="countries" optionLabel="name" />
|
||||
<label for="country">Country</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-field-checkbox">
|
||||
<Checkbox id="accept" name="accept" value="Accept" v-model="v$.accept.$model" :class="{'p-invalid':v$.accept.$invalid && submitted}" />
|
||||
<label for="accept" :class="{'p-error': v$.accept.$invalid && submitted}">I agree to the terms and conditions*</label>
|
||||
</div>
|
||||
<Button type="submit" label="Submit" class="p-mt-2" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AppDoc name="VuelidateFormDemo" :sources="sources" :service="['CountryService']" :data="['countries']" :dependencies="{'@vuelidate/core': '^2.0.0-alpha.14', '@vuelidate/validators': '^2.0.0-alpha.12'}"/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { email, required } from "@vuelidate/validators";
|
||||
import { useVuelidate } from "@vuelidate/core";
|
||||
import CountryService from '../../service/CountryService';
|
||||
|
||||
export default {
|
||||
setup: () => ({ v$: useVuelidate() }),
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
date: null,
|
||||
country: null,
|
||||
accept: null,
|
||||
submitted: false,
|
||||
countries: null,
|
||||
showMessage: false,
|
||||
sources: {
|
||||
'options-api': {
|
||||
tabName: 'Source',
|
||||
content: `
|
||||
<template>
|
||||
<div class="form-demo">
|
||||
<Dialog v-model:visible="showMessage" :breakpoints="{ '960px': '80vw' }" :style="{ width: '30vw' }" position="top">
|
||||
<div class="p-d-flex p-ai-center p-dir-col p-pt-6 p-px-3">
|
||||
<i class="pi pi-check-circle" :style="{fontSize: '5rem', color: 'var(--green-500)' }"></i>
|
||||
<h5>Registration Successful!</h5>
|
||||
<p :style="{lineHeight: 1.5, textIndent: '1rem'}">
|
||||
Your account is registered under name <b>{{name}}</b> ; it'll be valid next 30 days without activation. Please check <b>{{email}}</b> for activation instructions.
|
||||
</p>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="p-d-flex p-jc-center">
|
||||
<Button label="OK" @click="toggleDialog" class="p-button-text" />
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
|
||||
<div class="p-d-flex p-jc-center">
|
||||
<div class="card">
|
||||
<h5 class="p-text-center">Register</h5>
|
||||
<form @submit.prevent="handleSubmit(!v$.$invalid)" class="p-fluid">
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<InputText id="name" v-model="v$.name.$model" :class="{'p-invalid':v$.name.$invalid && submitted}" />
|
||||
<label for="name" :class="{'p-error':v$.name.$invalid && submitted}">Name*</label>
|
||||
</div>
|
||||
<small v-if="(v$.name.$invalid && submitted) || v$.name.$pending.$response" class="p-error">{{v$.name.required.$message.replace('Value', 'Name')}}</small>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label p-input-icon-right">
|
||||
<i class="pi pi-envelope" />
|
||||
<InputText id="email" v-model="v$.email.$model" :class="{'p-invalid':v$.email.$invalid && submitted}" aria-describedby="email-error"/>
|
||||
<label for="email" :class="{'p-error':v$.email.$invalid && submitted}">Email*</label>
|
||||
</div>
|
||||
<span v-if="v$.email.$error && submitted">
|
||||
<span id="email-error" v-for="(error, index) of v$.email.$errors" :key="index">
|
||||
<small class="p-error">{{error.$message}}</small>
|
||||
</span>
|
||||
</span>
|
||||
<small v-else-if="(v$.email.$invalid && submitted) || v$.email.$pending.$response" class="p-error">{{v$.email.required.$message.replace('Value', 'Email')}}</small>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<Password id="password" v-model="v$.password.$model" :class="{'p-invalid':v$.password.$invalid && submitted}" toggleMask>
|
||||
<template #header>
|
||||
<h6>Pick a password</h6>
|
||||
</template>
|
||||
<template #footer="sp">
|
||||
{{sp.level}}
|
||||
<Divider />
|
||||
<p class="p-mt-2">Suggestions</p>
|
||||
<ul class="p-pl-2 p-ml-2 p-mt-0" style="line-height: 1.5">
|
||||
<li>At least one lowercase</li>
|
||||
<li>At least one uppercase</li>
|
||||
<li>At least one numeric</li>
|
||||
<li>Minimum 8 characters</li>
|
||||
</ul>
|
||||
</template>
|
||||
</Password>
|
||||
<label for="password" :class="{'p-error':v$.password.$invalid && submitted}">Password*</label>
|
||||
</div>
|
||||
<small v-if="(v$.password.$invalid && submitted) || v$.password.$pending.$response" class="p-error">{{v$.password.required.$message.replace('Value', 'Password')}}</small>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<Calendar id="date" v-model="date" :showIcon="true" />
|
||||
<label for="date">Birthday</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<Dropdown id="country" v-model="country" :options="countries" optionLabel="name" />
|
||||
<label for="country">Country</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-field-checkbox">
|
||||
<Checkbox id="accept" name="accept" value="Accept" v-model="v$.accept.$model" :class="{'p-invalid':v$.accept.$invalid && submitted}" />
|
||||
<label for="accept" :class="{'p-error': v$.accept.$invalid && submitted}">I agree to the terms and conditions*</label>
|
||||
</div>
|
||||
<Button type="submit" label="Submit" class="p-mt-2" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { email, required } from "@vuelidate/validators";
|
||||
import { useVuelidate } from "@vuelidate/core";
|
||||
import CountryService from './service/CountryService';
|
||||
|
||||
export default {
|
||||
setup: () => ({ v$: useVuelidate() }),
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
date: null,
|
||||
country: null,
|
||||
accept: null,
|
||||
submitted: false,
|
||||
countries: null,
|
||||
showMessage: false
|
||||
}
|
||||
},
|
||||
countryService: null,
|
||||
validations() {
|
||||
return {
|
||||
name: {
|
||||
required
|
||||
},
|
||||
email: {
|
||||
required,
|
||||
email
|
||||
},
|
||||
password: {
|
||||
required
|
||||
},
|
||||
accept: {
|
||||
required
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.countryService = new CountryService();
|
||||
},
|
||||
mounted() {
|
||||
this.countryService.getCountries().then(data => this.countries = data);
|
||||
},
|
||||
methods: {
|
||||
handleSubmit(isFormValid) {
|
||||
this.submitted = true;
|
||||
|
||||
if (!isFormValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.toggleDialog();
|
||||
},
|
||||
toggleDialog() {
|
||||
this.showMessage = !this.showMessage;
|
||||
|
||||
if(!this.showMessage) {
|
||||
this.resetForm();
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
this.name = '';
|
||||
this.email = '';
|
||||
this.password = '';
|
||||
this.date = null;
|
||||
this.country = null;
|
||||
this.accept = null;
|
||||
this.submitted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
<\\/script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form-demo {
|
||||
.card {
|
||||
min-width: 450px;
|
||||
|
||||
form {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.p-field {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 960px) {
|
||||
.card {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
`
|
||||
},
|
||||
'composition-api': {
|
||||
tabName: 'Composition API',
|
||||
content: `
|
||||
<template>
|
||||
<div class="form-demo">
|
||||
<Dialog v-model:visible="showMessage" :breakpoints="{ '960px': '80vw' }" :style="{ width: '30vw' }" position="top">
|
||||
<div class="p-d-flex p-ai-center p-dir-col p-pt-6 p-px-3">
|
||||
<i class="pi pi-check-circle" :style="{fontSize: '5rem', color: 'var(--green-500)' }"></i>
|
||||
<h5>Registration Successful!</h5>
|
||||
<p :style="{lineHeight: 1.5, textIndent: '1rem'}">
|
||||
Your account is registered under name <b>{{state.name}}</b> ; it'll be valid next 30 days without activation. Please check <b>{{state.email}}</b> for activation instructions.
|
||||
</p>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="p-d-flex p-jc-center">
|
||||
<Button label="OK" @click="toggleDialog" class="p-button-text" />
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
|
||||
<div class="p-d-flex p-jc-center">
|
||||
<div class="card">
|
||||
<h5 class="p-text-center">Register</h5>
|
||||
<form @submit.prevent="handleSubmit(!v$.$invalid)" class="p-fluid">
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<InputText id="name" v-model="v$.name.$model" :class="{'p-invalid':v$.name.$invalid && submitted}" />
|
||||
<label for="name" :class="{'p-error':v$.name.$invalid && submitted}">Name*</label>
|
||||
</div>
|
||||
<small v-if="(v$.name.$invalid && submitted) || v$.name.$pending.$response" class="p-error">{{v$.name.required.$message.replace('Value', 'Name')}}</small>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label p-input-icon-right">
|
||||
<i class="pi pi-envelope" />
|
||||
<InputText id="email" v-model="v$.email.$model" :class="{'p-invalid':v$.email.$invalid && submitted}" aria-describedby="email-error"/>
|
||||
<label for="email" :class="{'p-error':v$.email.$invalid && submitted}">Email*</label>
|
||||
</div>
|
||||
<span v-if="v$.email.$error && submitted">
|
||||
<span id="email-error" v-for="(error, index) of v$.email.$errors" :key="index">
|
||||
<small class="p-error">{{error.$message}}</small>
|
||||
</span>
|
||||
</span>
|
||||
<small v-else-if="(v$.email.$invalid && submitted) || v$.email.$pending.$response" class="p-error">{{v$.email.required.$message.replace('Value', 'Email')}}</small>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<Password id="password" v-model="v$.password.$model" :class="{'p-invalid':v$.password.$invalid && submitted}" toggleMask>
|
||||
<template #header>
|
||||
<h6>Pick a password</h6>
|
||||
</template>
|
||||
<template #footer="sp">
|
||||
{{sp.level}}
|
||||
<Divider />
|
||||
<p class="p-mt-2">Suggestions</p>
|
||||
<ul class="p-pl-2 p-ml-2 p-mt-0" style="line-height: 1.5">
|
||||
<li>At least one lowercase</li>
|
||||
<li>At least one uppercase</li>
|
||||
<li>At least one numeric</li>
|
||||
<li>Minimum 8 characters</li>
|
||||
</ul>
|
||||
</template>
|
||||
</Password>
|
||||
<label for="password" :class="{'p-error':v$.password.$invalid && submitted}">Password*</label>
|
||||
</div>
|
||||
<small v-if="(v$.password.$invalid && submitted) || v$.password.$pending.$response" class="p-error">{{v$.password.required.$message.replace('Value', 'Password')}}</small>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<Calendar id="date" v-model="date" :showIcon="true" />
|
||||
<label for="date">Birthday</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-field">
|
||||
<div class="p-float-label">
|
||||
<Dropdown id="country" v-model="country" :options="countries" optionLabel="name" />
|
||||
<label for="country">Country</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-field-checkbox">
|
||||
<Checkbox id="accept" name="accept" value="Accept" v-model="v$.accept.$model" :class="{'p-invalid':v$.accept.$invalid && submitted}" />
|
||||
<label for="accept" :class="{'p-error': v$.accept.$invalid && submitted}">I agree to the terms and conditions*</label>
|
||||
</div>
|
||||
<Button type="submit" label="Submit" class="p-mt-2" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, ref, onMounted } from 'vue';
|
||||
import { email, required } from "@vuelidate/validators";
|
||||
import { useVuelidate } from "@vuelidate/core";
|
||||
import CountryService from './service/CountryService';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
onMounted(() => {
|
||||
countryService.value.getCountries().then(data => countries.value = data);
|
||||
})
|
||||
|
||||
const state = reactive({
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
accept: null
|
||||
});
|
||||
|
||||
const rules = {
|
||||
name: { required },
|
||||
email: { required, email },
|
||||
password: { required },
|
||||
accept: { required }
|
||||
};
|
||||
|
||||
const countryService = ref(new CountryService());
|
||||
const submitted = ref(false);
|
||||
const countries = ref();
|
||||
const showMessage = ref(false);
|
||||
const date = ref();
|
||||
const country = ref();
|
||||
|
||||
const v$ = useVuelidate(rules, state);
|
||||
|
||||
const handleSubmit = (isFormValid) => {
|
||||
submitted.value = true;
|
||||
|
||||
if (!isFormValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
toggleDialog();
|
||||
}
|
||||
const toggleDialog = () => {
|
||||
showMessage.value = !showMessage.value;
|
||||
|
||||
if(!showMessage.value) {
|
||||
resetForm();
|
||||
}
|
||||
}
|
||||
const resetForm = () => {
|
||||
state.name = '';
|
||||
state.email = '';
|
||||
state.password = '';
|
||||
state.date = null;
|
||||
state.country = null;
|
||||
state.accept = null;
|
||||
submitted.value = false;
|
||||
}
|
||||
|
||||
return { state, v$, handleSubmit, toggleDialog, submitted, countries, showMessage, date, country }
|
||||
}
|
||||
}
|
||||
<\\/script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form-demo {
|
||||
.card {
|
||||
min-width: 450px;
|
||||
|
||||
form {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.p-field {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 960px) {
|
||||
.card {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
`
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
countryService: null,
|
||||
validations() {
|
||||
return {
|
||||
name: {
|
||||
required
|
||||
},
|
||||
email: {
|
||||
required,
|
||||
email
|
||||
},
|
||||
password: {
|
||||
required
|
||||
},
|
||||
accept: {
|
||||
required
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.countryService = new CountryService();
|
||||
},
|
||||
mounted() {
|
||||
this.countryService.getCountries().then(data => this.countries = data);
|
||||
},
|
||||
methods: {
|
||||
handleSubmit(isFormValid) {
|
||||
this.submitted = true;
|
||||
|
||||
if (!isFormValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.toggleDialog();
|
||||
},
|
||||
toggleDialog() {
|
||||
this.showMessage = !this.showMessage;
|
||||
|
||||
if(!this.showMessage) {
|
||||
this.resetForm();
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
this.name = '';
|
||||
this.email = '';
|
||||
this.password = '';
|
||||
this.date = null;
|
||||
this.country = null;
|
||||
this.accept = null;
|
||||
this.submitted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form-demo {
|
||||
.card {
|
||||
min-width: 450px;
|
||||
|
||||
form {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.p-field {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 960px) {
|
||||
.card {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
Loading…
Reference in New Issue