Vuelidate & Tailwind: Why am I always seeing invalid errors? - vue.js

For the life of me I cannot seem to understand why I am always seeing the validation error(s). The logic is working great, it seems to all be in my :class binding(s) that I've got it all wrong. I know I'm going to feel really silly when I get this figured out, but after countless tutorials that I feel like I've literally copy/paste from, I'm still in the same boat.
Here is my template for email. The password input is the same...
<div class="relative">
<label for="email" class="sr-only block text-sm font-medium leading-5 text-gray-700">
Email address
</label>
<input type="email"
id="email"
v-model.trim="$v.user.email.$model"
:class="{ 'border-red-500': !$v.user.email.required}"
placeholder="Email"
class="mt-1 placeholder-gray-400 shadow appearance-none border rounded w-full py-3 px-3 text-gray-700 leading-tight transition duration-150 ease-in-out sm:text-sm sm:leading-5 focus:outline-none focus:border-gray-400 focus:shadow-outline-gray"
/>
<div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none"
v-if="!$v.user.email.required">
<svg
class="h-5 w-5 text-red-500"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fill-rule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
clip-rule="evenodd"
/>
</svg>
</div>
</div>
<div>
<p class="mt-2 text-sm text-red-600" v-if="!$v.user.email.required">
Email is required
</p>
<p class="mt-2 text-sm text-red-600" v-if="!$v.user.email.email">
Please use a valid email address
</p>
</div>
This is what my script block looks like:
data: () => ({
errors: false,
user: {
email: "",
password: "",
},
}),
validations: {
user: {
email: { required, email },
password: { required },
},
},
methods: {
async handleSignIn() {
this.$v.user.$touch();
this.empty = !this.$v.user.$anyDirty;
this.errors = this.$v.user.$anyError;
if (this.$v.$invalid) {
this.errors = true;
} else {
try {
...
}
}
}
As I enter a valid email and/or password, the validation errors go away. If I try to submit with invalid data, the validator is working properly. With a valid email/password, I'm able to successfully submit the form.
When the page first loads, here is what my form looks like. How can I correctly render the form to only show the errors if a field is invalid?
Thank you for any suggestions!

Try to add the $v.user.email.$error condition to the border class binding, the icon and the error message :
<div id="app">
<div class="relative">
<label for="email" class="sr-only block text-sm font-medium leading-5 text-gray-700">
Email address
</label>
<input type="email" id="email" v-model.trim="$v.user.email.$model" :class="{ 'border-red-500': $v.user.email.$error}" placeholder="Email" class="mt-1 placeholder-gray-400 shadow appearance-none border rounded w-full py-3 px-3 text-gray-700 leading-tight transition duration-150 ease-in-out sm:text-sm sm:leading-5 focus:outline-none focus:border-gray-400 focus:shadow-outline-gray" />
<div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none" v-if="!$v.user.email.required">
<svg v-if="$v.user.email.$error" class="h-5 w-5 text-red-500" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</div>
</div>
<div>
<p class="mt-2 text-sm text-red-600" v-if="$v.user.email.$error">
Email is required
</p>
<p class="mt-2 text-sm text-red-600" v-if="!$v.user.email.email">
Please use a valid email address
</p>
<button class="rounded w-full flex justify-center text-gray-100 bg-purple-700 hover:bg-purple-800 px-6 py-2 flex items-center">
Submit
</button>
</div>
</div>
LIVE DEMO

Related

Flowbite modal not showing

I am trying to use flowbite components in my project but they are not working , (e.g dropdown, modal,...).
I followed the documentation but nothing works.
I'm using vuejs 3, Vite v2.9.9.
This is my main.js file:
import { createApp } from 'vue'
import App from "#/App.vue";
import router from './router/index'
import store from './state/store'
// Imported css file [TailwindCSS]
import './index.css'
// Imported flowbite
import 'flowbite';
createApp(App)
.use(router)
.use(store)
.mount('#app')
modal.vue
<template>
<!-- Modal toggle -->
<button class="block text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" type="button" data-modal-toggle="default-modal">
Toggle modal
</button>
<!-- Main modal -->
<div id="default-modal" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed right-0 left-0 top-4 z-50 justify-center items-center h-modal md:h-full md:inset-0">
<div class="relative px-4 w-full max-w-2xl h-full md:h-auto">
<!-- Modal content -->
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
<!-- Modal header -->
<div class="flex justify-between items-start p-5 rounded-t border-b dark:border-gray-600">
<h3 class="text-xl font-semibold text-gray-900 lg:text-2xl dark:text-white">
Terms of Service
</h3>
<button type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white" data-modal-toggle="default-modal">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</button>
</div>
<!-- Modal body -->
test
<!-- Modal footer -->
<div class="flex items-center p-6 space-x-2 rounded-b border-t border-gray-200 dark:border-gray-600">
<button data-modal-toggle="default-modal" type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">I accept</button>
<button data-modal-toggle="default-modal" type="button" class="text-gray-500 bg-white hover:bg-gray-100 focus:ring-4 focus:ring-gray-300 rounded-lg border border-gray-200 text-sm font-medium px-5 py-2.5 hover:text-gray-900 focus:z-10 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-500 dark:hover:text-white dark:hover:bg-gray-600">Decline</button>
</div>
</div>
</div>
</div>
</template>
I had the same problem at svelte.
I finally solved it:
import 'flowbite/dist/flowbite.js'
...
let modal = new Modal(document.getElementById('modalId'),{placement:'center'})
...
<button on:cllick={()=>modal.show()} >Open</button>
Okay, so what I did to make it work is to create the Modal with Javascript (check here the flowbite documentation) instead of using this data-modal-toggle="defaultModal" property defined in the html component.
Find below an example with Vue3 Single File Component. For other frameworks the solution should be similar.
<template>
<!-- Modal toggle -->
<button class="block text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" type="button" #click="toggleModal">
Toggle modal
</button>
<!-- Main modal -->
<div id="defaultModal" tabindex="-1" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 w-full md:inset-0 h-modal md:h-full justify-center items-center">
<div class="relative p-4 w-full max-w-2xl h-full md:h-auto">
<!-- Modal content -->
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
<!-- Modal header -->
<div class="flex justify-between items-start p-4 rounded-t border-b dark:border-gray-600">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">
Terms of Service
</h3>
<button type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white" #click="toggleModal">
<svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
<span class="sr-only">Close modal</span>
</button>
</div>
<!-- Modal body -->
<div class="p-6 space-y-6">
<p class="text-base leading-relaxed text-gray-500 dark:text-gray-400">
With less than a month to go before the European Union enacts new consumer privacy laws for its citizens, companies around the world are updating their terms of service agreements to comply.
</p>
<p class="text-base leading-relaxed text-gray-500 dark:text-gray-400">
The European Union’s General Data Protection Regulation (G.D.P.R.) goes into effect on May 25 and is meant to ensure a common set of data rights in the European Union. It requires organizations to notify users as soon as possible of high-risk data breaches that could personally affect them.
</p>
</div>
<!-- Modal footer -->
<div class="flex items-center p-6 space-x-2 rounded-b border-t border-gray-200 dark:border-gray-600">
<button #click="toggleModal" type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">I accept</button>
<button #click="toggleModal" type="button" class="text-gray-500 bg-white hover:bg-gray-100 focus:ring-4 focus:outline-none focus:ring-blue-300 rounded-lg border border-gray-200 text-sm font-medium px-5 py-2.5 hover:text-gray-900 focus:z-10 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-500 dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-gray-600">Decline</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return{
modal: ''
}
},
methods: {
toggleModal() {
this.modal.toggle();
}
},
mounted() {
// set the modal menu element
const targetEl = document.getElementById('defaultModal');
// options with default values
const options = {
placement: 'center',
backdropClasses: 'bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40',
onHide: () => {
console.log('modal is hidden');
},
onShow: () => {
console.log('modal is shown');
},
onToggle: () => {
console.log('modal has been toggled');
}
};
this.modal = new Modal(targetEl, options);
}
}
</script>
This took me 2 weeks to figure out, I am using Vite with Vue.
I followed the instructions here https://flowbite.com/docs/getting-started/vue/
Where it didn't state to add the script tag
<script src="./node_modules/flowbite/dist/flowbite.js"></script>
in my index.html
Which is, stated in #3 https://flowbite.com/docs/getting-started/quickstart/

Adding class to element in v-for loop

I have a v-for loop, and I wanna make background: red; by adding a class. But when I click my action button it coloring all indexes.
My goal is if I have 3 elements when I click the priority button then make that line(index) background red. I mean list element make the background red/yellow/green whichever.
<div v-for="(item, index) in todos" :key="item.id">
<div :class="{'bg-red-500': isRed, 'bg-yellow-500': isYellow, 'bg-green-500': isGreen}" class="rounded transition ease-in-out delay-200 duraiton-200 flex align-middle justify-between">
<div id="checklist" #click="addCompleted(index)" class="w-1/2 break-all text-white transition duration-200 ease-out text-1xl text-left my-5 transition ease-in-out delay-150 duration-200 cursor-pointer flex justify-start align-center">
<input v-bind:id="item.id" type="checkbox" name="checkbox" class="outline-0 offset-0 ring-0 border-0 focus:outline-0 focus:ring-0 focus:offset-0 focus:border-0 focus:ring-offset-0" />
<label v-bind:for="item.id">{{ item.text }}</label>
</div>
<div class="priority flex items-center justify-between text-white">
<div #click="priortiy_red(index)" class="red rounded-full bg-red-500 p-2 "></div>
<div #click="priortiy_yellow(index)" class="yellow rounded-full bg-yellow-500 p-2 mx-2"></div>
<div #click="priortiy_green(index)" class="green rounded-full bg-green-500 p-2 "></div>
</div>
<span class="X-icon items-center justify-end inline-flex cursor-pointer" #click="removeTodo(index)">
<svg class="fill-current text-red-500" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" />
<path d="M0 0h24v24H0z" fill="none" />
</svg>
</span>
</div>
</div>
What I Try for now I try normal vuejs's class bind property. But as I say it coloring all divisions.
Github Repo Link: https://keremunce.github.io/Vue-ToDo/
A simple solution is to add a color prop to each todo object.
Then apply class with item.color === 'red' etc..
... 'bg-red-500': item.color === 'red', 'bg-yellow-500': item.color === 'yellow', 'bg-green-500': item.color === ''green ...
and apply color with:
...
#click="item.color = 'red'"
// etc
...

TypeError: Cannot read properties of undefined (reading 'required') at eval (validator-v2.vue?8194:311:1)

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?

Error in mounted hook: "TypeError: Cannot read properties of undefined (reading 'required')" in vuejs

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?

Vue2-medium editor styles not pulling in

I'm trying to work with this vue2-medium-editor based on this: https://github.com/FranzSkuffka/vue-medium-editor
I'm following the instructions but Im not getting the styles to load for some reason..
So, my first step I installed
yarn add vue2-medium-editor
Then I imported my component in:
<template>
<div class="flex flex-col h-screen">
<div class="grid place-items-center">
<!-- Auth Card -->
<div
class="w-full p-12 px-6 sm:px-10 bg-white rounded-lg shadow-md lg:shadow-lg"
>
<!-- <h2
class="text-center font-semibold text-3xl lg:text-4xl text-gray-800"
>
</h2> -->
<form method="POST">
<!-- Email Input -->
<input
id="title"
type="text"
name="title"
placeholder="Title of your story"
class="text-xl block w-full py-5 px-2 mt-2 text-gray-800 appearance-none border-b-2 border-gray-100 focus:text-gray-500 focus:outline-none focus:border-gray-200"
required
/>
<editor :content='content' :options='options'></editor>
</form>
<div class="mt-5 flex justify-between">
<router-link :to="{ name: 'write-story' }">
<button class="bg-transparent hover:bg-blue-500 text-blue-700 font-bold py-2 px-4 rounded inline-flex items-center border-2 border-blue-500 hover:text-white hover:border-transparent">
<svg class="ml-2 fill-current w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z"/></svg>
<span>Back</span>
</button>
</router-link>
<router-link :to="{ name: 'home' }">
<button class="bg-transparent hover:bg-blue-500 text-blue-700 font-bold py-2 px-4 rounded inline-flex items-center border-2 border-blue-500 hover:text-white hover:border-transparent">
<span>Submit</span>
</button>
</router-link>
</div>
</div>
</div>
</div>
</template>
<script>
import editor from 'vue2-medium-editor'
export default {
name: "new-question",
components: { editor },
data() {
return {
content: "test",
options: {
}
}
}
}
</script>
Theres a step in the documentation to include the required css and it points to the css on the base medium editor.
So, I installed medium editor with yarn add medium-editor
Then I included the styles like this based on this github repo: https://github.com/tui2tone/vue2-medium-editor =>
<style>
#import "~/medium-editor/dist/css/medium-editor.css";
#import "~/vue2-medium-editor/src/themes/default.css";
</style>
This is within the same file. It bult successfully but it doesnt seem to work.
This is what Im getting now:
What am I missing?
Edit 1
if I do this:
<style>
#import "medium-editor/dist/css/medium-editor.css";
#import "vue2-medium-editor/src/themes/default.css";
</style>
I get this error:
Uncaught Error: Cannot find module '-!../../../../node_modules/css-loader/index.js??ref--6-1!../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!./medium-editor/dist/css/medium-editor.css'
at webpackMissingModule (app.js:3172)
at Object../node_modules/css-loader/index.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/containers/Story/Create.vue?vue&type=style&index=0&lang=css& (app.js:3172)
at __webpack_require__ (app.js:20)
at Object../node_modules/style-loader/index.js!./node_modules/css-loader/index.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/containers/Story/Create.vue?vue&type=style&index=0&lang=css& (app.js:21655)
at __webpack_require__ (app.js:20)
at Module../resources/js/containers/Story/Create.vue?vue&type=style&index=0&lang=css& (app.js:61170)
at __webpack_require__ (app.js:20)
at Module../resources/js/containers/Story/Create.vue (app.js:61119)
at __webpack_require__ (app.js:20)
at Module../resources/js/router.js (app.js:61283)
```