How to bind a image with Vue JS - vue.js

I'm using Vue 3 and when I use :src in nothing appears on my site, I'm using one array with v-for. That's my code:
<BreezeDropdownLink2 v-for="(item, i) in itemsCart" :key="i" class=" hover:bg-gray-100 inline-flex w-full py-3 dark:hover:bg-gray-800">
<div class="justify-between inline-flex w-full">
<div class="rounded-md bg-gray-100 block h-12 dark:bg-vd2">
<img :src="item.image" class="w-16 h-12">
</div>
<div>
<p class="font-semibold text-gray-500 dark:text-gray-300" v-html="item.title"></p>
<span class="text-xs mb-10 text-gray-400" v-html="item.subtitle"></span>
</div>
<div class="inline-flex">
<NumberInput/>
<span class="font-semibold text-gray-500 ml-3 mt-5 dark:text-gray-300" v-html="'$'+item.price"></span>
<a #click="removeItem(item.id)" class="dark:text-gray-300"><svg data-v-c52069be="" xmlns="http://www.w3.org/2000/svg" width="14px" height="14px" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="cart-item-remove cursor-pointer feather feather-x"><line data-v-c52069be="" x1="18" y1="6" x2="6" y2="18"></line><line data-v-c52069be="" x1="6" y1="6" x2="18" y2="18"></line></svg></a>
</div>
</div>
</BreezeDropdownLink2>
The itemsCart is:
itemsCart:[{id: 1, title: 'Apple Watch <br> Series 5', price: 339.99, subtitle:'By Apple', image:'../Assets/Img/product1.png'}]

Wrap the images' path in a require call. The below code works fine for me.
<template>
<div>
<div v-for="item in itemsCart" :key="item.id">
<div>
<img :src="item.image" style="width:50px;height:50px" />
</div>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
itemsCart: [{
id: 0,
image: require('./assets/logo1.png')
},
{
id: 1,
image: require('./assets/logo2.png')
}
]
}
}
}
</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?

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.

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)
```

Is there a way to get the data from multiple selects as array?

I'm currently stuck on a task on VueJS. Basically I'm trying to create an array from multiple select inside a form to get all the data as an array or Object to process it further. I just searched but got no results or an idea on how to solve my issue.
Parent Component
<template>
<div id="product" class="mt-12">
<div class="flex flex-wrap mb-4">
<div class="w-1/2 pr-12">
<img src="https://placehold.it/800" alt="">
</div>
<div class="w-1/2">
<div class="flex justify-between content-center h-12 mb-4">
<div class="text-gray-700 py-2">
<h2 v-if="product.brand" class="leading-none font-bold text-sm">{{ product.brand }}</h2>
<h1 class="text-xl leading-snug">{{ product.name }}</h1>
</div>
<div class="text-gray-700 py-2">
<p class="text-xl font-bold leading-none">{{ product.price }}</p>
<p class="text-xs text-right leading-none">Inkl. 19% MwSt.</p>
</div>
</div>
<div class="divider bg-gray-400 mt-4 mb-4" />
<div id="variations">
<form action="">
<ProductVariation v-for="(variations, type) in product.variations" :type="type" :variations="variations" :key="type" v-model="form.variation"/>
<div class="flex w-full">
<button class="w-full leading-none bg-blue-500 hover:bg-blue-600 text-white py-2 rounded" type="submit">Add to cart</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
import ProductVariation from '#/components/products/ProductVariation'
export default {
data () {
return {
product: null,
form: {
variation: null
}
}
},
components: {
ProductVariation
},
async asyncData({ params, app }) {
let response = await app.$axios.$get(`products/${params.slug}`)
return {
product: response.data
}
}
}
</script>
ProductVariation Component
<template>
<div class="flex mb-4">
<div class="w-full">
<label class="block text-gray-700 w-full text-sm font-bold">{{ type }}</label>
<select class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight" :name="type">
<option value="0">Please select</option>
<option v-for="variation in variations" :key="variation.id" :value="variation.id">{{ variation.name }} <span>( +{{ variation.price }} )</span></option>
</select>
</div>
</div>
</template>
<script>
export default {
props: {
type: {
required: true,
type: String
},
variations: {
required: true,
type: Array
}
},
}
</script>