I really hit a wall with this issue. For an unknown reason (to me) Vuelidate doesn't validate the password field. No matter what you enter it is always invalid and I am not sure why. I tried different solutions but I always return that password is invalid. Does someone know where is the issue?
Here is the code that I am using:
<template>
<form
#submit="checkForm"
:action="this.action"
method="post"
novalidate="true"
>
<div class="app-form-wrapper mb-3 mb-md-0 pt-3 pb-1 py-md-0 rounded">
<!-- Email address -->
<div
class="form-group mb-3"
:class="{ 'form-error': $v.user.email.$error }"
>
<label for="email_login">Email address</label>
<input
type="email"
name="email"
class="form-control py-2 h-auto"
id="email_login"
ref="email"
placeholder="Your email"
aria-describedby="email_error"
v-model.trim.lazy="$v.user.email.$model"
autocomplete="off"
autofocus
/>
<div v-if="$v.user.email.$error">
<div
class="error mt-1"
id="email_error"
aria-live="assertive"
v-if="!$v.user.email.required"
>
Email address is required
</div>
</div>
</div>
<!-- Password -->
<div
class="form-group position-relative mb-0 mb-md-3"
:class="{ 'form-error': $v.user.password.$error }"
>
<div class="d-flex justify-content-between">
<label for="password_login">Password</label>
<a :href="this.forgotUrl" class=" mr-3 mr-md-0 text-muted"
><u>Forgot your password?</u></a
>
</div>
<input
:type="passwordFieldType"
name="password"
class="form-control py-2 h-auto"
id="password_login"
ref="password"
placeholder="Password"
aria-describedby="password_error"
v-model.trim.lazy="$v.user.password.$model"
autocomplete="off"
/>
<button
type="button"
id="switchVisibility"
class="position-absolute"
#click="switchVisibility"
></button>
<div v-if="$v.user.password.$error">
<div
class="error mt-1"
id="password_error"
aria-live="assertive"
v-if="$v.user.password.$dirty && !$v.user.password.required"
>
Password is required
</div>
</div>
</div>
</div>
<!-- CSRF -->
<input type="hidden" name="_token" :value="csrf" />
<!-- Submit -->
<button
class="btn btn-primary btn-lg btn-block"
type="submit"
id="loginBtn"
:disabled="submitStatus === 'PENDING'"
>
Login
</button>
<div class="text-center mt-2">
Don't have an account yet? Sign up here!
</div>
<div
class="bottom-validation--ok mt-2 text-center"
v-if="submitStatus === 'OK'"
>
Thanks for logging in!
</div>
<div
class="bottom-validation--error mt-2 text-center"
v-if="submitStatus === 'ERROR'"
>
Please fill the form correctly.
</div>
<div
class="bottom-validation--sending mt-2 text-center"
v-if="submitStatus === 'PENDING'"
>
Sending...
</div>
<div class="bottom-validation--error mt-2 text-center" v-if="errors">
<div v-for="value in errors">
{{ value }}
</div>
</div>
<hr />
<a
:href="googleUrl"
role="button"
id="btn-google"
class="btn btn-social btn-white btn-block border"
>
<svg
version="1.1"
id="google"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
viewBox="0 0 533.5 544.3"
style="enable-background: new 0 0 533.5 544.3"
xml:space="preserve"
class="mr-2"
>
<path
class="st0"
d="M533.5,278.4c0-18.5-1.5-37.1-4.7-55.3H272.1v104.8h147c-6.1,33.8-25.7,63.7-54.4,82.7v68h87.7
C503.9,431.2,533.5,361.2,533.5,278.4L533.5,278.4z"
/>
<path
class="st1"
d="M272.1,544.3c73.4,0,135.3-24.1,180.4-65.7l-87.7-68c-24.4,16.6-55.9,26-92.6,26c-71,0-131.2-47.9-152.8-112.3
H28.9v70.1C75.1,486.3,169.2,544.3,272.1,544.3z"
/>
<path
class="st2"
d="M119.3,324.3c-11.4-33.8-11.4-70.4,0-104.2V150H28.9c-38.6,76.9-38.6,167.5,0,244.4L119.3,324.3z"
/>
<path
class="st3"
d="M272.1,107.7c38.8-0.6,76.3,14,104.4,40.8l77.7-77.7C405,24.6,339.7-0.8,272.1,0C169.2,0,75.1,58,28.9,150
l90.4,70.1C140.8,155.6,201.1,107.7,272.1,107.7z"
/>
</svg>
<span>Log in with Google</span>
</a>
<a
:href="facebookUrl"
role="button"
id="btn-facebook"
class="btn btn-social btn-facebook btn-block shadow-sm border"
>
<svg
id="facebook"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
class="mr-2"
>
<path
class="st0"
d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"
/>
</svg>
<span>Log in with Facebook</span>
</a>
</form>
</template>
<script>
import Vuelidate from "vuelidate";
import { required } from "vuelidate/lib/validators";
//import './useragent.js';
Vue.use(Vuelidate);
export default {
props: {
action: String,
old: Object,
forgotUrl: String,
errors: Array,
facebookUrl: String,
googleUrl: String
},
data() {
return {
user: {
email: "",
password: ""
},
passwordFieldType: "password",
csrf: document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
submitStatus: null
};
},
validations: {
user: {
email: {
required
},
password: {
required
}
}
},
methods: {
checkForm(e) {
this.$v.user.$touch();
// For accessibility: focusing on the field with an error
if (this.$v.user.$invalid) {
e.preventDefault();
for (let key in Object.keys(this.$v.user)) {
const input = Object.keys(this.$v.user)[key];
if (input.includes("$")) return false;
if (this.$v.user[input].$error) {
this.$refs[input].focus();
break;
}
}
this.submitStatus = "ERROR";
} else {
return true;
}
},
switchVisibility() {
this.passwordFieldType =
this.passwordFieldType === "password" ? "text" : "password";
}
},
created() {
this.user = this.old;
}
};
</script>
<style scoped>
.form-error input {
border-color: #c91547;
}
.error,
.bottom-validation--error {
color: #c91547;
}
#switchVisibility {
bottom: 10px;
right: 10px;
background-color: transparent;
border: none;
opacity: 0.4;
font-size: 14px;
font-weight: 600;
}
#switchVisibility:focus,
#switchVisibility:active,
#switchVisibility:hover {
box-shadow: none;
outline: none;
}
input[type="password"] + button:before {
content: "Show";
}
input[type="text"] + button:before {
content: "Hide";
}
</style>
Try below steps it will help you to fix the issue.
Step 1: You forgot to import email from vuelidate/lib/validators
import { required, email } from 'vuelidate/lib/validators'
Step 2:
validations: {
user: {
email: { required, email },
password: { required }
}
},
Step 3: Do the validation on button click
checkForm(e) {
this.$v.$touch();
if (this.$v.$invalid) {
return // stop here if form is invalid
}
},
Step 4: Display error message in your html template
<div class="form-group mb-3" :class="{ 'form-error': $v.user.email.$error }">
<label for="email_login">Email address</label>
<input
type="email"
name="email"
class="form-control py-2 h-auto"
id="email_login"
ref="email"
placeholder="Your email"
aria-describedby="email_error"
v-model.trim.lazy="$v.user.email.$model"
autocomplete="off"
autofocus />
<div v-if="!$v.user.email.required" class="error mt-1" id="email_error" aria-live="assertive">
Email address is required
</div>
<div v-if="!$v.user.email.email" class="error mt-1" id="email_error" aria-live="assertive">
Invalid Email address
</div>
</div>
You can checkout for Vue,Vuex,Vuelidate,translation on Vue-vuex-vuelidate-i18n-registration-login-todo
Related
In my laravel and vue js application I have following vuejs to display a modal and insert some data
<template>
<div>
<modal-md :identifier="identifier" :has-multiple-actions="false">
<template slot="modal_title">
<div
class="
flex
justify-between
items-center
border-b border-certstyle-border
px-10
py-3
"
>
<h3
class="
text-2xl
leading-10
text-certstyle-titles
font-bold
my-2
flex
items-center
"
>
<span
class="border-l-2 border-certstyle-orange inline-block h-6 mr-2"
></span>
<span>Add document</span>
</h3>
<div
class="
h-full
flex
items-center
cs--reveal
transition-all
duration-500
"
></div>
</div>
</template>
<template slot="modal_content">
<!--Modal content-->
<div
class="bg-certstyle-background-light w-full h-full px-10 pt-8 pb-10"
>
<!--Name-->
<div class="mb-5 relative z-30">
<p class="text-certstyle-titles font-bold text-sm mb-1">Name</p>
<validator-v2
identifier="addDocument"
name="add_name_input"
selector="id"
></validator-v2>
<input
id="add_name_input"
v-model="documentName"
name="name"
type="text"
class="form-input w-full relative z-10"
/>
</div>
<div class="flex justify-between">
<!--Completed at-->
<div class="w-1/2 mr-2">
<p class="text-certstyle-titles font-bold text-sm mb-1">
Date of issue
</p>
<validator-v2
identifier="addDocument"
name="issued_at"
:rules="{ required: { message: 'Date of issue is required.' } }"
>
<div class="h-12">
<cs-date-picker
id="minimumDate"
v-model="dateOfIssue"
:default-selection="true"
name="issued_at"
>
</cs-date-picker>
</div>
</validator-v2>
</div>
<!--Expiration date-->
<div class="w-1/2 ml-2">
<p class="text-certstyle-titles font-bold text-sm mb-1">
Expiry date
</p>
<validator-v2
identifier="addDocument"
name="expires_at"
depends-on-name="does_not_expire"
:rules="{ required: { message: 'Expiry date is required.' } }"
>
<div class="h-12">
<cs-date-picker
id="maximumDate"
v-model="expiryDate"
:default-selection="true"
:disable="doesNotExpire"
name="expires_at"
>
</cs-date-picker>
</div>
</validator-v2>
</div>
</div>
<div class="flex justify-between">
<!--Completed at-->
<div class="w-1/2 mr-2">
<div class="mb-4">
<label
class="
inline-flex
items-center
focus:outline-none
checkbox--container
mt-2
"
>
<input
v-model="doesNotExpire"
type="checkbox"
name="does_not_expire"
/>
<span
class="checkbox--checkmark flex items-center justify-center"
>
<svg
class="icon text-certstyle-orange feather feather-check"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</span>
<span
style="bottom: 4px"
class="text-certstyle-text font-normal text-sm relative"
>This document does not expire</span
>
</label>
</div>
</div>
</div>
<!--Upload document-->
<div class="mb-1">
<dashboard-input-label
identifier="document"
:settings="{ help: true, helpDirection: 'left' }"
>
Upload document
<template slot="helpText">
Maximum filesize is 5 MB. The default allowed file extensions
are: pdf, jpeg and png.
</template>
</dashboard-input-label>
<validator-v2
:identifier="identifier"
name="document_file"
:rules="{ required: { message: 'Document is required.' } }"
>
<custom-file-upload
ref="documentDocument"
v-model="documentFile"
:max-upload-file-size="5"
name="document_file"
></custom-file-upload>
</validator-v2>
</div>
<!--Document number-->
<div class="mb-1">
<p
class="inline-block text-certstyle-titles font-bold text-sm mb-1"
>
Document Number
</p>
<div class="relative">
<input
id="add_document_number_input"
v-model="documentNumber"
name="document_number"
:disabled="doesNotHaveDocumentNumber"
type="text"
class="form-input w-full relative z-10"
/>
<input-annotation identifier="document_number">
Fill in your document number here.
<span class="font-bold"> Note!</span>
Use the document number mentioned on the qualification you
upload. Don\'t use your WINDA-ID.
</input-annotation>
<label
class="
inline-flex
items-center
focus:outline-none
checkbox--container
mt-2
"
>
<input
v-model="doesNotHaveDocumentNumber"
type="checkbox"
name="no_document_number"
/>
<span
class="checkbox--checkmark flex items-center justify-center"
>
<svg
class="icon text-certstyle-orange feather feather-check"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</span>
<span
style="bottom: 4px"
class="text-certstyle-text font-normal text-sm relative"
>
This document has no document number.
</span>
</label>
</div>
</div>
</div>
</template>
<template slot="modal_actions">
<div class="flex items-center justify-between space-x-4">
<disables-submit-on-errors
:identifier="identifier"
#proceed="addNewDocument"
>
<loading-button ref="submitBtnSave" size="normal">
Save & Close
</loading-button>
</disables-submit-on-errors>
<disables-submit-on-errors
:identifier="identifier"
#proceed="storeDocumentAndAddNew"
>
<loading-button ref="submitBtn" size="normal">
Save & Add new
</loading-button>
</disables-submit-on-errors>
</div>
</template>
</modal-md>
<div class="flex flex-col fixed top-0 right-0 z-50">
<toastr-alert
v-if="message !== ''"
:message="message"
:type="type"
#hidden="resetToastrMessage"
>
</toastr-alert>
</div>
</div>
</template>
<script>
import ModalMd from '#/components/dashboard/sharedComponents/modals/modal-md'
import CheckboxWarning from '#/components/inputs/checkbox-warning/checkbox-warning'
import CsDataPicker from '#/components/inputs/cs-data-picker/cs-data-picker'
import HasToastrMessage from '#/Mixins/HasToastrMessage'
import Helper from '#/Support/Helper'
const url = window.location.href
const url_split = url.split('/')
const emp_id_location = url_split.length - 2
const emp_id = url_split[emp_id_location]
export default {
name: 'AddDocument',
components: { CsDataPicker, CheckboxWarning, ModalMd },
mixins: [HasToastrMessage],
props: ['identifier', 'selectedDocumentId'],
data() {
return {
documentId: null,
documentName: null,
dateOfIssue: null,
expiryDate: null,
documentNumber: null,
doesNotHaveDocumentNumber: false,
doesNotExpire: false,
documentFile: null,
doesOptIn: false,
isAddNew: false,
}
},
watch: {
doesNotHaveDocumentNumber() {
if (this.doesNotHaveDocumentNumber) {
this.documentNumber = null
}
},
},
mounted() {
if (this.selectedDocumentId) {
this.documentId = this.selectedDocumentId
}
},
methods: {
addDocument(documentId) {
this.documentId = documentId
},
storeDocumentAndAddNew() {
this.isAddNew = true
const loader = this.$refs.submitBtn
this.storeDocument(loader)
},
addNewDocument() {
const loader = this.$refs.submitBtnSave
this.storeDocument(loader)
},
storeDocument(loader) {
loader.startLoading()
if (!this.documentNumber && !this.doesNotHaveDocumentNumber) {
this.showToastrErrorMessage(
'Document number is required unless you confirm it does not apply'
)
loader.stopLoading()
return
}
if (!this.expiryDate && !this.doesNotExpire) {
this.showToastrErrorMessage(
'Expiry date is required unless you confirm it does not apply'
)
loader.stopLoading()
return
}
const formData = new FormData()
formData.append('emp_id', emp_id)
formData.append('name', this.documentId)
// formData.append('name', this.documentName)
formData.append(
'issued_at',
moment(this.dateOfIssue).format('DD-MM-YYYY')
)
formData.append(
'expires_at',
moment(this.expiryDate).format('DD-MM-YYYY')
)
formData.append(
'document_number',
!this.doesNotHaveDocumentNumber ? this.documentNumber : null
)
if (this.doesNotExpire) {
formData.append('does_not_expire', this.doesNotExpire)
}
formData.append('opt_in', this.doesOptIn)
formData.append('document_file', this.$refs.documentDocument.file)
this.$store
.dispatch('addDocument', formData)
.then((data) => {
this.showToastrSuccessMessage('Document added successfully')
if (!this.isAddNew) {
eventsHub.$emit(`overlay:close:${this.identifier}`)
}
this.reset()
this.$emit('created')
})
.catch((error) => {
if (
Helper.isset(error.response.data) &&
Helper.isset(error.response.data.errors)
) {
collect(error.response.data.errors).each((error) => {
this.showToastrErrorMessage(error[0])
})
}
})
.finally(() => {
loader.stopLoading()
})
},
reset() {
this.documentNumber = null
this.doesNotHaveDocumentNumber = false
this.doesNotExpire = false
this.documentFile = null
this.doesOptIn = false
this.isAddNew = false
},
},
}
</script>
But when I try to run this, it shows me an console error saying
TypeError: Cannot read properties of undefined (reading 'required')
And when I click on the submit button, it just start to show the loading spinner without submitting the form.
What's the mistake I'm doing here?
in my laravel vue application I have following vue modal to upload a document
<template>
<div>
<modal-md :identifier="identifier" :has-multiple-actions="false">
<template slot="modal_title">
<div class="flex justify-between items-center border-b border-certstyle-border px-10 py-3">
<h3 class="text-2xl leading-10 text-certstyle-titles font-bold my-2 flex items-center">
<span class="border-l-2 border-certstyle-orange inline-block h-6 mr-2"></span>
<span>Add document</span>
</h3>
<div class="h-full flex items-center cs--reveal transition-all duration-500"></div>
</div>
</template>
<template slot="modal_content">
<!--Modal content-->
<div class="bg-certstyle-background-light w-full h-full px-10 pt-8 pb-10">
<!--Name-->
<div class="mb-5 relative z-30">
<p class="text-certstyle-titles font-bold text-sm mb-1">Name</p>
<div class="h-12 relative z-10">
<input value="" name="name" id="add_name_input" type="text" class=" form-input w-full relative z-10" >
</div>
<validator identifier="addDocument" name="add_name_input" selector="id" ></validator>
</div>
<div class="flex justify-between">
<!--Completed at-->
<div class="w-1/2 mr-2">
<p class="text-certstyle-titles font-bold text-sm mb-1">Date of issue</p>
<validator-v2 identifier="addDocument" name="issued_at" :rules="{ required: { message: 'Date of issue is required.'}}">
<div class="h-12">
<cs-date-picker
id="minimumDate"
v-model="dateOfIssue"
:default-selection="true"
name="issued_at">
</cs-date-picker>
</div>
</validator-v2>
</div>
<!--Expiration date-->
<div class="w-1/2 ml-2">
<p class="text-certstyle-titles font-bold text-sm mb-1">Expiry date</p>
<validator-v2 identifier="addDocument" name="expires_at" depends-on-name="does_not_expire" :rules="{ required: { message: 'Expiry date is required.'}}">
<div class="h-12">
<cs-date-picker
id="maximumDate"
v-model="expiryDate"
:default-selection="true"
:disable="doesNotExpire"
name="expires_at">
</cs-date-picker>
</div>
</validator-v2>
</div>
</div>
<div class="flex justify-between">
<!--Completed at-->
<div class="w-1/2 mr-2">
<div class="mb-4">
<label class="inline-flex items-center focus:outline-none checkbox--container mt-2">
<input type="checkbox" name="does_not_expire" v-model="doesNotExpire">
<span class="checkbox--checkmark flex items-center justify-center ">
<svg class="icon text-certstyle-orange feather feather-check" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</span>
<span style="bottom: 4px;" class="text-certstyle-text font-normal text-sm relative">This document does not expire</span>
</label>
</div>
</div>
</div>
<!--Upload document-->
<div class="mb-1">
<dashboard-input-label identifier="document" :settings="{help: true, helpDirection: 'left'}">
Upload document
<template slot="helpText">
Maximum filesize is 5 MB.
The default allowed file extensions are: pdf, jpeg and png.
</template>
</dashboard-input-label>
<validator-v2 :identifier="identifier" name="document_file" :rules="{ required: { message: 'Document is required.'}}">
<custom-file-upload :max-upload-file-size="5" name="document_file" v-model="documentFile" ref="documentDocument"></custom-file-upload>
</validator-v2>
</div>
<!--Document number-->
<div class="mb-1">
<p class="inline-block text-certstyle-titles font-bold text-sm mb-1">Document Number</p>
<div class="relative">
<input v-model="documentNumber" name="document_number" id="add_document_number_input" :disabled="doesNotHaveDocumentNumber" type="text" class=" form-input w-full relative z-10" >
<input-annotation identifier="document_number">
Fill in your document number here.
<span class="font-bold"> Note!</span>
Use the document number mentioned on the qualification you upload. Don\'t use your WINDA-ID.
</input-annotation>
<label class="inline-flex items-center focus:outline-none checkbox--container mt-2">
<input type="checkbox" name="no_document_number" v-model="doesNotHaveDocumentNumber">
<span class="checkbox--checkmark flex items-center justify-center">
<svg class="icon text-certstyle-orange feather feather-check" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</span>
<span style="bottom: 4px;" class="text-certstyle-text font-normal text-sm relative">
This document has no document number.
</span>
</label>
</div>
</div>
</div>
</template>
<template slot="modal_actions">
<div class="flex items-center justify-between space-x-4">
<disables-submit-on-errors
:identifier="identifier"
#proceed="addNewDocument"
>
<loading-button ref="submitBtnSave" size="normal">
Save & Close
</loading-button>
</disables-submit-on-errors>
<disables-submit-on-errors
:identifier="identifier"
#proceed="storeDocumentAndAddNew"
>
<loading-button ref="submitBtn" size="normal">
Save & Add new
</loading-button>
</disables-submit-on-errors>
</div>
</template>
</modal-md>
<div class="flex flex-col fixed top-0 right-0 z-50">
<toastr-alert
v-if="message !== ''"
:message="message"
:type="type"
#hidden="resetToastrMessage">
</toastr-alert>
</div>
</div>
</template>
<script>
import ModalMd from "#/components/dashboard/sharedComponents/modals/modal-md";
import CheckboxWarning from "#/components/inputs/checkbox-warning/checkbox-warning";
import CsDataPicker from "#/components/inputs/cs-data-picker/cs-data-picker";
import HasToastrMessage from "#/Mixins/HasToastrMessage";
import Helper from "#/Support/Helper";
var url = window.location.href;
var url_split = url.split("/");
var emp_id_location = url_split.length - 2;
var emp_id = url_split[emp_id_location];
export default {
name: "add-document",
props: ['identifier', 'selectedDocumentId'],
mixins: [HasToastrMessage],
components: {CsDataPicker, CheckboxWarning, ModalMd},
data() {
return {
certificadocumentId: null,
dateOfIssue: null,
expiryDate: null,
documentNumber: null,
doesNotHaveDocumentNumber: false,
doesNotExpire: false,
documentFile: null,
doesOptIn: false,
isAddNew: false,
}
},
watch: {
doesNotHaveDocumentNumber() {
if(this.doesNotHaveDocumentNumber) {
this.documentNumber = null
}
}
},
mounted() {
if(this.selectedDocumentId) {
this.documentId = this.selectedDocumentId
}
},
methods: {
addDocument(documentId) {
this.documentId = documentId
},
storeDocumentAndAddNew() {
this.isAddNew = true
const loader = this.$refs.submitBtn;
this.storeDocument(loader)
},
addNewDocument() {
const loader = this.$refs.submitBtnSave;
this.storeDocument(loader)
},
storeDocument(loader) {
loader.startLoading();
if(!this.documentNumber && !this.doesNotHaveDocumentNumber) {
this.showToastrErrorMessage("Document number is required unless you confirm it does not apply")
loader.stopLoading();
return
}
if(!this.expiryDate && !this.doesNotExpire) {
this.showToastrErrorMessage("Expiry date is required unless you confirm it does not apply")
loader.stopLoading();
return
}
const formData = new FormData()
formData.append('emp_id', emp_id)
formData.append('issued_at', moment(this.dateOfIssue).format('DD-MM-YYYY'))
formData.append('expires_at', moment(this.expiryDate).format('DD-MM-YYYY'))
formData.append('document_number', !this.doesNotHaveDocumentNumber
? this.documentNumber
: null)
if(this.doesNotExpire) {
formData.append('does_not_expire', this.doesNotExpire)
}
formData.append('opt_in', this.doesOptIn)
formData.append('document_file',this.$refs.documentDocument.file)
this.$store.dispatch('addDocument', formData).then((data) => {
this.showToastrSuccessMessage("Document added successfully")
if(!this.isAddNew) {
eventsHub.$emit(`overlay:close:${this.identifier}`)
}
this.reset()
this.$emit('created')
}).catch((error) => {
if(Helper.isset(error.response.data) &&Helper.isset(error.response.data.errors)) {
collect(error.response.data.errors).each((error) => {
this.showToastrErrorMessage(error[0])
});
}
}).finally(() => { loader.stopLoading()})
},
reset() {
this.documentNumber = null
this.doesNotHaveDocumentNumber = false
this.doesNotExpire = false
this.documentFile = null
this.doesOptIn = false
this.isAddNew = false
},
}
}
</script>
<style scoped>
</style>
but when I run this, it gives me an console error saying, Error in mounted hook: "TypeError: Cannot read properties of undefined (reading 'required')"
I'm using the same code for another model and it works fine, and apart from the console error once when I hit the submit, it's just showing me the loading spinner, without saving the data to db
What's I'm doing wrong and how to fix it?
I developed one page which is responsible for displaying cart items and the response is coming from backend upto this it's working fine .Now inside same page one more registration page is there and that also integrated with backend API, after successfully registered it should be redirected to /orderSuccess page but it's not redirecting ,Here what is the issue please help me How to fix this issue.
After registered it changes my url path /cart to /ordersuccess also but page is not displaying..please help me to fix this issue
Cart.vue
<template>
<div class="main">
<div class="first-section">
<div class="content">
<h5>My Cart({{books.length}})</h5>
</div>
<div v-for="book in books" :key="book.id" class="container">
<div class="mid-section">
<img v-bind:src="book.file" alt="not found">
<p class="title-section">{{book.name}}</p>
</div>
<div class="author-section">
<p class="author-name">by {{book.author}}</p>
</div>
<div class="price-section">
<h6>Rs.{{book.price}}</h6>
</div>
<div class="icons">
<i class="fas fa-minus-circle"></i>
<input class="rectangle" value=1>
<i class="fas fa-plus-circle"></i>
</div>
</div>
<div class="btn-grps">
<button class="btn" v-on:click="flip()" v-if="hide==true" type="submit">Place Order</button>
</div>
</div>
<div class="second -section">
<div class="details-box">
<input type="text" v-if="hide==true" class="initial-btn" placeholder="Customer Details" />
</div>
<div v-if="hide==false" class="fill-details">
<form #submit.prevent="" class="address">
<h4 class="heading">Customer Details</h4>
<div class="name">
<input type="name" required pattern="[A-Za-z]{3,10}" v-model="name">
<label class="label">Name</label>
</div>
<div class="name">
<input type="text" required v-model="phoneNumber">
<label class="label">Phone Number</label>
</div>
<div class="pin">
<input type="text" required v-model="pincode">
<label class="label">PinCode</label>
</div>
<div class="pin">
<input type="text" required v-model="locality">
<label class="label">Locality</label>
</div>
<div class="address-block">
<input class="address" type="text" required v-model="address">
<label id="Add" class="label">Address</label>
</div>
<div class="city-landMark">
<input type="text" required v-model="city">
<label class="label">City/Town</label>
</div>
<div class="city-landMark">
<input type="text" required v-model="landmark">
<label class="label">LandMark</label>
</div>
<div class="Radio-Buttons">
<p>Type</p>
<div class="radio-btns flex-container">
<div>
<input type="radio" id="Home" value="Home" name="type" v-model="type">
<div class="first-radio"> <label class="home" for="Home">Home</label></div>
</div>
<div>
<input class="work-round" type="radio" id="Work" value="Work" name="type" v-model="type">
<div class="second-radio"> <label for="Work" class="work-label">Work</label></div>
</div>
<div>
<input class="other-round" type="radio" id="Other" value="Other" name="type" v-model="type">
<div class="third-radio"><label for="Other">Other</label></div>
</div>
</div>
<div class="btn-continue">
<button type="submit" #click="handlesubmit();" class="continue">continue</button>
</div>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
import service from '../service/User'
export default {
beforeMount() {
// if (localStorage.getItem("reloaded")) {
// localStorage.removeItem("reloaded");
// } else {
// localStorage.setItem("reloaded", "1");
// location.reload();
// }
service.userDisplayCart().then(response => {
this.books = response.data;
})
},
data() {
return {
flag: true,
hide: true,
booksCount: 0,
name: '',
phoneNumber: '',
pincode: '',
locality: '',
city: '',
address: '',
landmark: '',
type: '',
books: []
}
},
methods: {
flip() {
this.hide = !this.hide;
},
Togglebtn() {
this.flag = !this.flag;
},
handlesubmit() {
let userData = {
name: this.name,
phoneNumber: this.phoneNumber,
pincode: this.pincode,
locality: this.locality,
city: this.city,
address: this.address,
landmark: this.landmark,
type: this.type,
}
service.customerRegister(userData).then(response => {
alert("user registered successfully");
this.$router.push('/ordersuccess');
return response;
})
}
}
}
</script>
<style lang="scss" scoped>
#import "#/styles/Cart.scss";
</style>
router.js
{
path:'/dashboard',
component:Dashboard,
children:[{
path:'/displaybooks',
component:DisplayBooks
},
{
path:'/sortLowtoHigh',
component:sortBooksLowtoHigh
},
{
path:'/sortHightoLow',
component:sortBooksHightoLow
},
{
path:'/cart',
component:Cart
},
{
path:'/ordersuccess',
component:OrderPlace
},
]
}
You can use the history mode on your router settings. This should fix the issue
const routes = {
path: 'Dashboard',
....
}
new VueRouter({routes, mode: 'history'});
this.$router.push({ path: '/ordersuccess' })
https://router.vuejs.org/guide/essentials/navigation.html
Hopefully this is a newbie question.
I am using Vuelidate to validate my form and the form validations works fine, when the “send email” button is clicked.However on success, instead of showing me the successful message, the system shows that all the form controls have errors(This is because I have bound the name, email, message controls to their corresponding empty data elements).
What am I missing?
How can I fix this issue?
Contact.vue
<template>
<div>
<section class="slice slice-lg" id="sct_contact_form">
<div class="container">
<div class="mb-5 text-center">
<span class="badge badge-soft-info badge-pill badge-lg">
Contact
</span>
<h3 class=" mt-4">Send us a message</h3>
</div>
<div class="row justify-content-center">
<div class="col-lg-8">
<form>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Name</label>
<input class="form-control" type="text" placeholder="Name" v-model="user.name" id="name" name="name" :class="{ 'is-invalid': submitted && $v.user.name.$error }" >
<div v-if="submitted && !$v.user.name.required" class="invalid-feedback">Name is required</div>
</div>
</div>
</div>
<div class="row align-items-center">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Email</label>
<input class="form-control" type="email" placeholder="email#example.com"
v-model="user.email" id="email" name="email" :class="{ 'is-invalid': submitted && $v.user.email.$error }" >
<div v-if="submitted && $v.user.email.$error" class="invalid-feedback">
<span v-if="!$v.user.email.required">Email is required</span>
<span v-if="!$v.user.email.email">Email is invalid</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Message</label>
<textarea class="form-control" data-toggle="autosize" placeholder="Tell us a few words ..." rows="3" style="overflow: hidden; overflow-wrap: break-word; resize: none; height: 96.9922px;"
v-model="user.message" id="message" name="message" :class="{ 'is-invalid': submitted && $v.user.message.$error }" ></textarea>
<div v-if="submitted && $v.user.message.$error" class="invalid-feedback">
<span v-if="!$v.user.message.required">Message is required</span>
<span v-if="!$v.user.message.minLength">Message must be at least 6 characters</span>
</div>
</div>
</div>
</div>
<div class="text-center mt-4">
<button type="button" class="btn btn-dark rounded-pill" v-on:click="SendEmail()">Send your message</button>
<span class="d-block mt-4 text-sm">We'll get back to you in 24-48 h.</span>
<div v-if="submitted" class="valid-feedback">
<span v-if="!$v.user.name.$error && !$v.user.email.$error && !$v.user.message.$error">Your email was send successfully. We'll get back to you in 24-48 h.</span>
</div>
</div>
</form>
</div>
</div>
</div>
</section>
</div>
</template>
import { Email } from '../api/email.js';
import { required, email, minLength, sameAs } from "vuelidate/lib/validators";
export default {
name: "Contact",
components:{
},
data() {
return {
user: {
name: "",
email: "",
message: ""
},
submitted: false
};
},
validations: {
user: {
name: { required },
email: { required, email },
message: { required, minLength: minLength(6) }
}
},
methods: {
SendEmail() {
this.submitted = true;
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
var nameWithEmailText="Email message from: "+ this.user.name + "\nEmail message: " + this.user.message;
var subject="Email from contact us page in common membership website";
Meteor.call('email.send', this.user.email, subject, nameWithEmailText);
this.user.name='';
this.user.email='';
this.user.message='';
}
}
}
You should wait for the Meteor.call() to complete, then reset the validation state.
For example
Meteor.call('email.send', this.user.email, subject, nameWithEmailText, (error, result) => {
this.user.name = ''
this.user.email = ''
this.user.message = ''
this.$v.$reset()
})
Trying to become friends with VUEJS. Got stuck on some simple stuff, couldn't google it. So I'm using MuseUi framework in my App. Well I want to do a simple thing, change the value of the property for each specific element on hover
<mu-paper :zDepth="1" v-on:mouseover=" ???? " class="searchBox">
I need to change:zDepth to 3 for example, on hover of the element. How could I achieve that?
full code snippet
<template>
<div>
<div class="column is-one-quarter">
<mu-paper :zDepth="paperHover" v-on:mouseover="changePaper" class="searchBox">
<mu-text-field fullWidth="true" :hintText="searchHint" v-model="query" class="demo-radio"/><br/>
<mu-radio label="Name" name="group" nativeValue="1" v-model="selected" class="demo-radio"/>
<mu-radio label="Manager" name="group" nativeValue="2" v-model="selected" class="demo-radio"/>
<mu-radio label="Department" name="group" nativeValue="3" v-model="selected" class="demo-radio"/>
<mu-radio label="Stage" name="group" nativeValue="4" v-model="selected" class="demo-radio"/>
<mu-radio label="Deadline" name="group" nativeValue="5" v-model="selected" class="demo-radio"/>
<mu-radio label="Start Date" name="group" nativeValue="6" v-model="selected" class="demo-radio"/>
</mu-paper>
</div>
<div class="column is-one-column">
<mu-float-button icon="add" v-on:click="openModal"/>
</div>
<div class="column">
<draggable v-model="projects" #start="drag=true" #end="drag=false">
<transition-group name="list-complete staggered-fade" tad="ul" :css="false" :before-enter="beforeEnter" :enter="enter" :leave="leave">
<li v-for="(project, index) in projectsComputed" :key="project.name" :data-index="index" class="column is-one-third list-complete-item">
<mu-paper :zDepth="3">
<mu-icon-button icon="delete" class="delete-button"></mu-icon-button>
<article class="media">
<div class="media-content">
<div class="content">
<div class="project-name has-text-centered">
<span>{{project.name}}</span>
</div>
<mu-badge :content="project.stage.name" primary slot="right"/>
<!--<div class="project-status has-text-centered">-->
<!--<span>{{project.stage.name}}</span>-->
<!--</div>-->
<div class="project-desc-list has-text left">
<span>Manager: </span> <span>{{project.manager.name}}</span>
</div>
<div class="project-desc-list has-text left">
<span>Department: </span> <span>{{project.department.name}}</span>
</div>
<div class="project-desc-list has-text left">
<span>Start Date: </span> <span>{{project.started_from}}</span>
</div>
<div class="project-desc-list has-text left">
<span>Dealine: </span> <span>{{project.deadline}}</span>
</div>
<p class="project-description">
{{project.description}}
</p>
</div>
</div>
</article>
</mu-paper>
</li>
</transition-group>
</draggable>
</div>
<div id="modal-ter" :class="[isActive ? activeClass : '', modal]">
<div class="modal-background" v-on:click="openModal"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Add New Project</p>
<button v-on:click="openModal" class="delete"></button>
</header>
<section class="modal-card-body">
<div class="column is-one-third">
<div class="field">
<label class="label">Project Name</label>
<p class="control">
<input class="input" v-model="newProject.name" type="text" placeholder="Text input">
</p>
</div>
</div>
<div class="column is-one-third">
<div class="field">
<label class="label">Project Description</label>
<p class="control">
<input class="input" v-model="newProject.description" type="text" placeholder="Text input">
</p>
</div>
</div>
<div class="column is-one-third">
<div class="field">
<label class="label">Start Date</label>
<p class="control">
<input class="input" v-model="newProject.started_from" type="text" placeholder="Text input">
</p>
</div>
</div>
<div class="column is-one-third">
<div class="field">
<label class="label">Deadline</label>
<p class="control">
<input class="input" v-model="newProject.deadline" type="text" placeholder="Text input">
</p>
</div>
</div>
<div class="column is-one-third">
<div class="field">
<label class="label">Manager</label>
<p class="control">
<input class="input" v-model="newProject.manager.name" type="text" placeholder="Text input">
</p>
</div>
</div>
<div class="column is-one-third">
<div class="field">
<label class="label">Department</label>
<p class="control">
<input class="input" v-model="newProject.department.name" type="text" placeholder="Text input">
</p>
</div>
</div>
<div class="column is-one-third">
<div class="field">
<label class="label">Stage</label>
<p class="control">
<input class="input" type="text" v-model="newProject.stage.name" placeholder="Text input">
</p>
</div>
</div>
</section>
<footer class="modal-card-foot">
<a v-on:click="createProject" class="button is-success">Save changes</a>
<a class="button">Cancel</a>
</footer>
</div>
</div>
</div>
</template>
<style scoped>
.demo-radio {
min-width: 8em;
}
.searchBox {
padding: 2em;
}
.project-status {
position: absolute;
top: 0.3em;
left: 0.3em;
background-color: #ffdb57;
padding: 0.2em;
padding-left: 0.5em;
padding-right: 0.5em;
border-radius: 0.3em;
}
.project-name {
font-weight: 900;
}
.project-description {
margin-top: 0.5em;
padding-top: 1em;
border-top: 1px solid lightgrey;
}
.project-desc-list span:first-of-type{
font-weight: 900;
}
.box {
position: relative;
}
.project-name {
text-align: center;
}
.delete-button {
background-color: rgba(255, 8, 8, 0.4);
transition: all .25s ease-in;
float: right;
position: absolute;
right: 0.3em;
top: 0.3em;
}
.delete-button:hover, .delete-button:focus{
background-color: rgba(255, 0, 0, 0.68);
}
.column{
display: inline-block;
padding: 1em;
}
.list-complete-item {
transition: all 1s;
}
.list-complete-enter, .list-complete-leave-active {
opacity: 0;
}
</style>
<script >
export default {
data(){
return {
loading: false,
isActive: false,
paperHover: 3,
modal: 'modal',
searchHint: 'Search by ...',
activeClass: 'is-active',
query: "",
selected: "",
projects: [],
newProject: {
name: '',
description: '',
started_from: '',
deadline: '',
manager: {
name: ''
},
department: {
name: ''
},
stage: {
name: ''
}
},
}
},
options: {
segmentShowStroke: false
},
mounted() {
this.getData();
},
computed: {
projectsComputed: function () {
var vm = this;
if(this.selected == '1' || this.selected == ""){
this.searchHint = "Search by Name";
return this.projects.filter(function (project) {
return project.name.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1;
})
}else if(this.selected == '2'){
this.searchHint = "Search by Manager";
return this.projects.filter(function (project) {
return project.manager.name.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1;
})
}else if(this.selected == '3'){
this.searchHint = "Search by Department";
return this.projects.filter(function (project) {
return project.department.name.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1;
})
}else if(this.selected == '4'){
this.searchHint = "Search by Stage";
return this.projects.filter(function (project) {
return project.stage.name.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1;
})
}else if(this.selected == '5'){
this.searchHint = "Search by Deadline";
return this.projects.filter(function (project) {
return project.deadline.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1;
})
}else if(this.selected == '6'){
this.searchHint = "Search by Start Date";
return this.projects.filter(function (project) {
return project.started_from.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1;
})
}
}
},
methods: {
changePaper: function () {
this.paperHover = 6 ;
},
beforeEnter: function (el) {
el.style.opacity = 0
el.style.height = 0
},
enter: function (el, done) {
var delay = el.dataset.index * 150
setTimeout(function () {
Velocity(
el,
{ opacity: 1, height: '1.6em' },
{ complete: done }
)
}, delay)
},
leave: function (el, done) {
var delay = el.dataset.index * 150
setTimeout(function () {
Velocity(
el,
{ opacity: 0, height: 0 },
{ complete: done }
)
}, delay)
},
getData() {
this.loading = true;
axios.get('/project/').then(({data}) => this.projects = data).then(() => this.loading = false)
},
openModal: function(){
if(this.isActive){
this.isActive = false;
}else {
this.isActive = true;
}
},
createProject() {
axios.post('project/store', this.newProject)
}
}
}
</script>
enter code here
The easiest way is probably to wrap the mu-paper component in another component where you can encapsulate the hover behavior.
// MuPaperHover.vue
<template>
<mu-paper :z-depth="zDepth" #mouseenter.native="zDepth = 3" #mouseleave.native="zDepth = 1">
<slot/>
</mu-paper>
</template>
<script>
export default {
data() {
return {
zDepth: 1,
};
},
};
</script>
You can then use mu-paper-hover in place of mu-paper.
I'm not familiar with MuseUI. However, I've written a Vue.js training course. In Vue, the area where your "????" are, should be a JavaScript expression. A typical practice is to call a method on your Vue instance that would then update the value of the property for the specific element. Without more details, it's hard to provide specifics.
The bottom line is, the "????" can be a JavaScript expression.