How to run #headlessui/vue in Nuxt 3 project? - vue.js

I'm trying to run #headlessui/vue package in Nuxt3 project.
I'm able to see the package in node_modules folder.
But I keep getting below error
Internal server error: Failed to resolve import "#headlessui/vue" from "components/LeftSideFilter.vue". Does the file exist?
LeftSideFilter.vue file code
<!--
This example requires Tailwind CSS v2.0+
This example requires some changes to your config:
```
// tailwind.config.js
module.exports = {
// ...
plugins: [
// ...
require('#tailwindcss/forms'),
],
}
```
-->
<template>
<div class="bg-white">
<div>
<!-- Mobile filter dialog -->
<TransitionRoot as="template" :show="mobileFiltersOpen">
<Dialog
as="div"
class="fixed inset-0 flex z-40 lg:hidden"
#close="mobileFiltersOpen = false"
>
<TransitionChild
as="template"
enter="transition-opacity ease-linear duration-300"
enter-from="opacity-0"
enter-to="opacity-100"
leave="transition-opacity ease-linear duration-300"
leave-from="opacity-100"
leave-to="opacity-0"
>
<DialogOverlay class="fixed inset-0 bg-black bg-opacity-25" />
</TransitionChild>
<TransitionChild
as="template"
enter="transition ease-in-out duration-300 transform"
enter-from="translate-x-full"
enter-to="translate-x-0"
leave="transition ease-in-out duration-300 transform"
leave-from="translate-x-0"
leave-to="translate-x-full"
>
<div
class="ml-auto relative max-w-xs w-full h-full bg-white shadow-xl py-4 pb-12 flex flex-col overflow-y-auto"
>
<div class="px-4 flex items-center justify-between">
<h2 class="text-lg font-medium text-gray-900">Filters</h2>
<button
type="button"
class="-mr-2 w-10 h-10 bg-white p-2 rounded-md flex items-center justify-center text-gray-400"
#click="mobileFiltersOpen = false"
>
<span class="sr-only">Close menu</span>
<XIcon class="h-6 w-6" aria-hidden="true" />
</button>
</div>
<!-- Filters -->
<form class="mt-4 border-t border-gray-200">
<h3 class="sr-only">Categories</h3>
<ul role="list" class="font-medium text-gray-900 px-2 py-3">
<li v-for="category in subCategories" :key="category.name">
<a :href="category.href" class="block px-2 py-3">
{{ category.name }}
</a>
</li>
</ul>
<Disclosure
as="div"
v-for="section in filters"
:key="section.id"
class="border-t border-gray-200 px-4 py-6"
v-slot="{ open }"
>
<h3 class="-mx-2 -my-3 flow-root">
<DisclosureButton
class="px-2 py-3 bg-white w-full flex items-center justify-between text-gray-400 hover:text-gray-500"
>
<span class="font-medium text-gray-900">
{{ section.name }}
</span>
<span class="ml-6 flex items-center">
<PlusSmIcon
v-if="!open"
class="h-5 w-5"
aria-hidden="true"
/>
<MinusSmIcon
v-else
class="h-5 w-5"
aria-hidden="true"
/>
</span>
</DisclosureButton>
</h3>
<DisclosurePanel class="pt-6">
<div class="space-y-6">
<div
v-for="(option, optionIdx) in section.options"
:key="option.value"
class="flex items-center"
>
<input
:id="`filter-mobile-${section.id}-${optionIdx}`"
:name="`${section.id}[]`"
:value="option.value"
type="checkbox"
:checked="option.checked"
class="h-4 w-4 border-gray-300 rounded text-indigo-600 focus:ring-indigo-500"
/>
<label
:for="`filter-mobile-${section.id}-${optionIdx}`"
class="ml-3 min-w-0 flex-1 text-gray-500"
>
{{ option.label }}
</label>
</div>
</div>
</DisclosurePanel>
</Disclosure>
</form>
</div>
</TransitionChild>
</Dialog>
</TransitionRoot>
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div
class="relative z-10 flex items-baseline justify-between pt-24 pb-6 border-b border-gray-200"
>
<h1 class="text-4xl font-extrabold tracking-tight text-gray-900">
New Arrivals
</h1>
<div class="flex items-center">
<Menu as="div" class="relative inline-block text-left">
<div>
<MenuButton
class="group inline-flex justify-center text-sm font-medium text-gray-700 hover:text-gray-900"
>
Sort
<ChevronDownIcon
class="flex-shrink-0 -mr-1 ml-1 h-5 w-5 text-gray-400 group-hover:text-gray-500"
aria-hidden="true"
/>
</MenuButton>
</div>
<transition
enter-active-class="transition ease-out duration-100"
enter-from-class="transform opacity-0 scale-95"
enter-to-class="transform opacity-100 scale-100"
leave-active-class="transition ease-in duration-75"
leave-from-class="transform opacity-100 scale-100"
leave-to-class="transform opacity-0 scale-95"
>
<MenuItems
class="origin-top-right absolute right-0 mt-2 w-40 rounded-md shadow-2xl bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
>
<div class="py-1">
<MenuItem
v-for="option in sortOptions"
:key="option.name"
v-slot="{ active }"
>
<a
:href="option.href"
:class="[
option.current
? 'font-medium text-gray-900'
: 'text-gray-500',
active ? 'bg-gray-100' : '',
'block px-4 py-2 text-sm',
]"
>
{{ option.name }}
</a>
</MenuItem>
</div>
</MenuItems>
</transition>
</Menu>
<button
type="button"
class="p-2 -m-2 ml-5 sm:ml-7 text-gray-400 hover:text-gray-500"
>
<span class="sr-only">View grid</span>
<ViewGridIcon class="w-5 h-5" aria-hidden="true" />
</button>
<button
type="button"
class="p-2 -m-2 ml-4 sm:ml-6 text-gray-400 hover:text-gray-500 lg:hidden"
#click="mobileFiltersOpen = true"
>
<span class="sr-only">Filters</span>
<FilterIcon class="w-5 h-5" aria-hidden="true" />
</button>
</div>
</div>
<section aria-labelledby="products-heading" class="pt-6 pb-24">
<h2 id="products-heading" class="sr-only">Products</h2>
<div class="grid grid-cols-1 lg:grid-cols-4 gap-x-8 gap-y-10">
<!-- Filters -->
<form class="hidden lg:block">
<h3 class="sr-only">Categories</h3>
<ul
role="list"
class="text-sm font-medium text-gray-900 space-y-4 pb-6 border-b border-gray-200"
>
<li v-for="category in subCategories" :key="category.name">
<a :href="category.href">
{{ category.name }}
</a>
</li>
</ul>
<Disclosure
as="div"
v-for="section in filters"
:key="section.id"
class="border-b border-gray-200 py-6"
v-slot="{ open }"
>
<h3 class="-my-3 flow-root">
<DisclosureButton
class="py-3 bg-white w-full flex items-center justify-between text-sm text-gray-400 hover:text-gray-500"
>
<span class="font-medium text-gray-900">
{{ section.name }}
</span>
<span class="ml-6 flex items-center">
<PlusSmIcon
v-if="!open"
class="h-5 w-5"
aria-hidden="true"
/>
<MinusSmIcon v-else class="h-5 w-5" aria-hidden="true" />
</span>
</DisclosureButton>
</h3>
<DisclosurePanel class="pt-6">
<div class="space-y-4">
<div
v-for="(option, optionIdx) in section.options"
:key="option.value"
class="flex items-center"
>
<input
:id="`filter-${section.id}-${optionIdx}`"
:name="`${section.id}[]`"
:value="option.value"
type="checkbox"
:checked="option.checked"
class="h-4 w-4 border-gray-300 rounded text-indigo-600 focus:ring-indigo-500"
/>
<label
:for="`filter-${section.id}-${optionIdx}`"
class="ml-3 text-sm text-gray-600"
>
{{ option.label }}
</label>
</div>
</div>
</DisclosurePanel>
</Disclosure>
</form>
<!-- Product grid -->
<div class="lg:col-span-3">
<RightSide />
<RightSide /> <RightSide /> <RightSide />
</div>
</div>
</section>
</main>
</div>
</div>
</template>
<script>
import RightSide from "./RightSide.vue";
import { ref } from "vue";
import {
Dialog,
DialogOverlay,
Disclosure,
DisclosureButton,
DisclosurePanel,
Menu,
MenuButton,
MenuItem,
MenuItems,
TransitionChild,
TransitionRoot,
} from "#headlessui/vue";
import { XIcon } from "#heroicons/vue/outline";
import {
ChevronDownIcon,
FilterIcon,
MinusSmIcon,
PlusSmIcon,
ViewGridIcon,
} from "#heroicons/vue/solid";
const sortOptions = [
{ name: "Most Popular", href: "#", current: true },
{ name: "Best Rating", href: "#", current: false },
{ name: "Newest", href: "#", current: false },
{ name: "Price: Low to High", href: "#", current: false },
{ name: "Price: High to Low", href: "#", current: false },
];
const subCategories = [
{ name: "Totes", href: "#" },
{ name: "Backpacks", href: "#" },
{ name: "Travel Bags", href: "#" },
{ name: "Hip Bags", href: "#" },
{ name: "Laptop Sleeves", href: "#" },
];
const filters = [
{
id: "color",
name: "Color",
options: [
{ value: "white", label: "White", checked: false },
{ value: "beige", label: "Beige", checked: false },
{ value: "blue", label: "Blue", checked: true },
{ value: "brown", label: "Brown", checked: false },
{ value: "green", label: "Green", checked: false },
{ value: "purple", label: "Purple", checked: false },
],
},
{
id: "category",
name: "Category",
options: [
{ value: "new-arrivals", label: "New Arrivals", checked: false },
{ value: "sale", label: "Sale", checked: false },
{ value: "travel", label: "Travel", checked: true },
{ value: "organization", label: "Organization", checked: false },
{ value: "accessories", label: "Accessories", checked: false },
],
},
{
id: "size",
name: "Size",
options: [
{ value: "2l", label: "2L", checked: false },
{ value: "6l", label: "6L", checked: false },
{ value: "12l", label: "12L", checked: false },
{ value: "18l", label: "18L", checked: false },
{ value: "20l", label: "20L", checked: false },
{ value: "40l", label: "40L", checked: true },
],
},
];
export default {
components: {
Dialog,
DialogOverlay,
Disclosure,
DisclosureButton,
DisclosurePanel,
Menu,
MenuButton,
MenuItem,
MenuItems,
TransitionChild,
TransitionRoot,
ChevronDownIcon,
FilterIcon,
MinusSmIcon,
PlusSmIcon,
ViewGridIcon,
XIcon,
RightSide,
},
setup() {
const mobileFiltersOpen = ref(false);
return {
sortOptions,
subCategories,
filters,
mobileFiltersOpen,
};
},
};
</script>

Related

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?

I'm doing a questions list and trying to change the color of every question but instead it changes the color of all questions

I'm doing a questions list and every question that I added have 3 options delete, Undo and Set Color. So when I try to change the color of one question to orange it changes all the background color for all questions.
Template :
<template>
<div class="container" id="app">
<h1>Vragenlijst</h1>
<div class="pol">
<input type="text" v-model="que" :class="inputCls" autofocus>
<span class="addBtn">
<button #click="inputCls='inputbox extend'"
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full"
v-if="!showIcon">Add question</button>
<button #click="addqueS"
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full"
v-else>Add</button>
</span>
</div>
<div class="section">
<ul class="queS" v-if="queS.length > 0">
<transition-group name="list" tag="p">
<li :style="{ 'background-color': cueCardColor }" v-for="(item, i) in queS" :key="item" :class="+ cueCardColor">
<span :class="{complete: item.completed}">{{ item.task }}</span>
<span>
<button #click="undoComplete(i)"
class="bg-yellow-500 hover:bg-yellow-700 text-white font-bold py-2 px-4 rounded-full"
v-if="item.completed">undo</button>
<button #click="undoComplete(i)"
class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded-full"
v-else>check</button>
<button #click="deleteque(i)"
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded-full">Delete</button>
<select class="bg-gray-500" v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
</span>
</li>
</transition-group>
</ul>
<h3 v-else>No question to display. Add one.</h3>
</div>
</div>
</div>
</template>
I think the problem is that not every question has an id. cueCardColor() checks for the color that is selected.
export default {
name: "App",
data() {
return {
selected: 'this',
options: [
{ text: 'Select color'},
{ text: 'Gray', value: 'gray' },
{ text: 'Orange', value: 'orange' },
{ text: 'Green', value: 'green' }
],
que: '',
queS: [],
showIcon: false,
inputCls: 'inputbox',
};
},
watch: {
que(value) {
if(value.length > 2) {
this.showIcon = true;
}
else {
this.showIcon = false;
}
}
},
methods: {
addqueS() {
this.inputCls = 'inputbox';
this.queS.unshift(
{
task: this.que,
completed: false
}
);
this.que = '';
setTimeout(() => {
this.showIcon = false;
}, 1000);
},
undoComplete(index) {
this.queS[index].completed = !this.queS[index].completed;
},
deleteque(index) {
this.queS.splice(index, 1);
},
},
computed: {
cueCardColor() {
if(this.selected!='Select color'){
return this.selected
}
return 'transparent'
},
}

VueJS 3 - How to use draggable nested element but prevent duplicate item

I am trying to create a simple survey builder with Vue3 and Vue Draggable. All is going well until I try to create a multiple choice question. This type of questions has its own sortable list of possible answers. When I add another multiple choice question it then pulls from the same list which makes sense but I have tried to use a v-if to check the parents ID to match the choice ID..
Basically if I add a new choice it adds to the all multiple choice questions, which makes sense, but how to I keep it to the current item I am in?
Any ideas? I know the code is mess, it will be refactored once it works.
<template>
<div class="p-4">
<div class="container mx-auto rounded-md grid grid-cols-12 gap-4 h-full">
<div class="col-span-4 p-3 flex flex-col min-h-screen bg-gray-200 shadow-md rounded-md">
<div class="text-lg font-bold w-full bg-blue-600 text-white rounded-md p-2 mb-4">Builder your survey</div>
<div class="sticky top-4">
<div class="text-lg font-bold">Components</div>
<draggable
class="p-2 rounded-md"
:list="componentsList"
:group="{ name: 'questions', pull: 'clone', put: false, sort: false }"
:clone="cloneItem"
sort: false
#change="log"
item-key="id"
>
<template #item="{ element }">
<div
class="bg-gray-300 p-4 rounded-md mt-2 shadow-sm hover:shadow-md cursor-pointer border border-blue-800 border-dashed"
>
{{ element.name }}
</div>
</template>
</draggable>
</div>
</div>
<div class="col-span-8 flex p-3 flex-col bg-white shadow-md rounded-md">
<div class="text-lg font-bold pt-4">Survey</div>
<draggable
class="w-full h-full border border-blue-400 rounded-md p-2 flex flex-col flex-1"
:list="questionsList"
group="questions"
#change="log"
handle=".handle"
itemKey="name + index"
>
<template #item="{ element, index }">
<div>
<div v-if="element.name == 'Single Line of Text'" class="bg-gray-300 p-2 rounded-md mt-2 mb-2 shadow-lg hover:shadow-md">
<div class="w-full text-sm text-left">{{ element.name }} {{element.id}}</div>
<div class="flex justify-between items-center p-2 bg-gray-200 rounded-md mb-4">
<div class="w-10 font-bold hidden">Q{{ index + 1 }}</div>
<div class="w-full pr-4">
<input
type="text"
class="w-full p-2 bg-transparent flex-grow"
placeholder="Question title here..."
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div #click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
<div>
<input
type="text"
class="w-full p-2 rounded-md border border-gray-400"
placeholder="User response will go here"
/>
</div>
<div class="text-left flex justify-between items-center p-2 bg-gray-200 rounded-md mt-2">
<div class="flex items-center">
<div><input type="checkbox" class="mr-2" /></div>
<div>Required?</div>
</div>
</div>
</div>
<!-- START problem area -->
<div v-else-if="element.name == 'Multiple Choice'" class="bg-gray-300 p-2 rounded-md mt-2 mb-2 shadow-lg hover:shadow-md">
<div class="w-full text-sm text-left">{{ element.name }} {{element.id}}</div>
<div class="flex justify-between items-center p-2 bg-gray-200 rounded-md mb-4">
<div class="w-10 font-bold hidden">Q{{ index + 1 }}</div>
<div class="w-full pr-4">
<input
type="text"
class="w-full p-2 bg-transparent flex-grow"
placeholder="Question title here..."
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div #click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
<div class="flex items-center ">
<draggable
class="p-2 rounded-md w-full"
:list="multipleChoiceList"
:group="{ name: 'choice', pull: false, put: false, sort: true }"
sort: true
handle=".handle"
#change="log"
item-key="question"
>
<template #item="{ element }">
<div
class="bg-blue-100 p-4 flex items-center justify-start rounded-md mt-2 shadow-sm hover:shadow-md cursor-pointer w-full"
>
<div class="flex items-center flex-grow"
>
<input type="checkbox" class="w-6 h-6">
<input
type="text"
class="p-2 bg-transparent flex-grow"
placeholder="Add choice here"
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-1x mr-2"></i>
</div>
<div #click="remove(index)">
<i class="las la-trash-alt text-red-800 la-1x cursor-pointer"></i>
</div>
</div>
</div>
</template>
<template #footer>
<div>
<button class="p-2 bg-blue-300 mt-2 rounded-md" #click="addChoice(element.id)">Add</button>
</div>
</template>
</draggable>
</div>
<div class="text-left flex justify-between items-center p-2 bg-gray-200 rounded-md mt-2">
<div class="flex items-center">
<div><input type="checkbox" class="mr-2" /></div>
<div>Required?</div>
</div>
</div>
</div>
<!-- END problem area -->
<div v-else-if="element.name == 'Open Ended'" class="bg-gray-300 p-2 rounded-md mt-2 mb-2 shadow-lg hover:shadow-md">
<div class="w-full text-sm text-left">{{ element.name }} {{element.id}}</div>
<div class="flex justify-between items-center p-2 bg-gray-200 rounded-md mb-4">
<div class="w-10 font-bold hidden">Q{{ index + 1 }}</div>
<div class="w-full pr-4">
<input
type="text"
class="w-full p-2 bg-transparent flex-grow"
placeholder="Question title here..."
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div #click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
<div>
<textarea
class="h-32 w-full w-full p-2 rounded-md border border-gray-400"
></textarea>
</div>
<div class="flex items-center">
<div>Max Length</div>
<div>
<input
type="number"
class="mr-2 w-20 border border-gray-400 p-2 rounded-md ml-2"
/>
</div>
</div>
<div class="text-left flex justify-between items-center p-2 bg-gray-200 rounded-md mt-2">
<div class="flex items-center">
<div><input type="checkbox" class="mr-2" /></div>
<div>Required?</div>
</div>
</div>
</div>
<div v-else-if="element.name == 'Divider'">
<div class="flex items-center">
<div class="flex-grow border-t border-black mx-4"> </div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div #click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
</div>
</div>
</template>
</draggable>
</div>
</div>
</div>
</template>
See Clone method which assigns a random number as the id
<script>
import draggable from "vuedraggable";
export default {
name: "Survey",
components: {
draggable,
},
data() {
return {
drag: false,
componentsList: [
{ name: "Single Line of Text", type: "question", text: "", id: 1 },
{ name: "Multiple Choice", type: "question", text: "", id: 2 },
{ name: "Matrix", type: "question", text: "", id: 3 },
{ name: "Open Ended", type: "question", text: "", id: 4 },
{ name: "Divider", type: "component", id: 9 },
],
questionsList: [],
multipleChoiceList: [
{text: "text A", type:"choice", question:"32"},
{text: "text B", type:"choice", question:"1"},
{text: "text A", type:"choice", question:"2"} ]
};
},
methods: {
onEnd: function(evt) {
console.log(evt);
},
log: function(evt) {
console.log(evt);
},
addChoice(id) {
this.multipleChoiceList.push({ text: "Choice " + id, type: "choice", question:id });
console.log(this.multipleChoiceList);
},
remove(index) {
this.questionsList.splice(index, 1);
},
cloneItem({ id, name, type }) {
return {
name: name,
id: Math.ceil(Math.random()*100),
text: "",
type: type,
};
}
},
mounted() {
// console.log("mounted");
},
};
</script>
https://github.com/SortableJS/Vue.Draggable/issues/687#issuecomment-1153083717
I just answered to a similar question on github.
Not sure would this help as Vue.Draggable and vue.draggable.next is slightly different.

How to update radio-buttons group based on selection

I have a working on a Responsive yes/no questionnaire where user can select either yes/no on each of the posed questions.
I want each questionCard component to have a radio-button group (yes/no). The radio-circles should be hidden and only label should be visible. Clicking on the label should select the appropiate option.
ALL THIS WORKS
My issue comes in when I re-size the window! The layout changes appropietly but the radio selection is gone.
Any Ideas how I can keep the selection regardless the window size?
CodeSandbox
App.vue
<template>
<parent-component />
</template>
<script>
import parentComponent from "./components/parentComponent.vue";
export default {
name: "App",
components: {
parentComponent,
},
};
</script>
<style>
</style>
Parent.vue
<template>
<div>
<question-card
v-for="car in objectData.cars.data"
:key="car.id"
:carData="car"
></question-card>
</div>
</template>
<script>
import questionCard from "./questionCard.vue";
export default {
name: "App",
components: {
questionCard,
},
data() {
return {
objectData: {
cars: {
data: [
{
id: 1,
name: "Do You Like Tesla?",
},
{
id: 2,
name: "Do You Like BMW?",
},
{
id: 3,
name: "Do You Like AUDI?",
},
],
},
},
};
},
};
</script>
Questioncard.vue
<template>
<br />
<br />
<div class="hidden sm:block">
<h1>Lage Screen</h1>
<h2 class="font-bold">{{ carData.name }}</h2>
<div class="flex items-center justify-center">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'yes'"
/>
<label
:for="carData.id + 'yes'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>Yes</span>
</label>
</div>
<div class="flex items-center justify-center">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'no'"
/>
<label
:for="carData.id + 'no'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>No</span>
</label>
</div>
</div>
<div class="sm:hidden">
<h1>Small Screen</h1>
<h2 class="font-bold">{{ carData.name }}</h2>
<div class="flex items-center w-1/2 justify-center">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'yes'"
/>
<label
:for="carData.id + 'yes'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>Yes</span>
</label>
</div>
<div class="flex items-center w-1/2 justify-center">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'no'"
/>
<label
:for="carData.id + 'no'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>No</span>
</label>
</div>
</div>
</template>
<script>
export default {
props: ["carData"],
data() {
return {
selected: null,
};
},
methods: {
onChange(event) {
this.selected = event.target.value;
},
},
};
</script>
<style scoped>
input[type="radio"] {
display: none;
}
input[type="radio"]:checked + label {
background-color: #78be20;
}
</style>
I see you are using TailwindCSS. You can control the sizes with w-1/2 sm:w-full on the elements
You don't need different input for the different screen sizes. Like this
<div class="">
<h1>Any size Screen</h1>
<h2 class="font-bold">{{ carData.name }}</h2>
<div class="flex items-center justify-center w-1/2 sm:w-full">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'yes'"
/>
<label
:for="carData.id + 'yes'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>Yes</span>
</label>
</div>
<div class="flex items-center justify-center w-1/2 sm:w-full">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'no'"
/>
<label
:for="carData.id + 'no'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>No</span>
</label>
</div>
</div>