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
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/
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
...
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'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)
```