I have image upload form for images to my website. When the user clicks on input images, he can choose multiple images. After selecting images, images are previewed and the user can select some meta info(Category, Type) about the image.
upload.vue
<template> <div> <div> //Universal category select. this selection will apply to all comp. <v-select placeholder="Select Category" class="mt-2 md:w-1/2" :options="category" v-model="parentDesignCategory" /> <v-select placeholder="Select Type" class="mt-2 md:w-1/2" :options="type" v-model="parentDesignType" /> </div> <input type="file" accept="image/*" name="images" @change="uploadImage" id="images" multiple /> <div class="flex flex-wrap"> <div class="md:w-1/2" v-for="(file, index) in files" :key="index"> <transition name="fade"> <AdminFileUpload :file="file" :type="type" :category="category" :parentDesignType="parentDesignType" :parentDesignCategory="parentDesignCategory" @delete-row="deleteThisRow(index)" /> </transition> </div> </div> </div> </template> <script> export default { name: "admin", // middleware: "auth", data: function() { return { files: [], parentDesignType: null, parentDesignCategory: null, type: ["1", "2", "3"], category: ["a","b","c" ] }; }, components: {}, methods: { uploadImage(event) { let file = event.target.files; for (let i = 0; i < file.length; i++) { this.files.push(file[i]); } }, deleteThisRow: function(index) { this.files.splice(index, 1); } } }; </script> <style scoped> .fade-enter-active { transition: opacity 1.5s; } .fade-leave-active { opacity: 0; } .fade-enter, .fade-leave-to { opacity: 0; } </style>
And if all image falls in one category than a user can select one category from this page and all component follows this category.
fileUpload.vue Component
<template> <div> <div class="m-4"> <form @submit.prevent="uploadImage" class="flex flex-wrap w-full shadow-lg border border-black" action="/upload" > <div class="w-full md:w-1/2 p-2"> <div class="relative pb-1/1"> <img :src="imageSrc" class="w-full absolute h-full" /> </div> </div> <div class="flex flex-col w-full md:w-1/2 p-2"> <v-select placeholder="Select Category" class="mt-2" :options="category" v-model="designCategory" ></v-select> <v-select placeholder="Select Type" class="mt-2" :options="type" v-model="designType" ></v-select> <input placeholder="likes" class="w-full text-black border-2 mt-2 p-3 rounded-lg focus:outline-none focus:shadow-outline" type="number" v-model="designLikes" /> <button @click="removeSelf" class="uppercase h-12 text-lg font-bold tracking-wide bg-primary text-gray-100 mt-2 p-3 rounded-lg w-full cursor-pointer" type="button" > Cancel </button> <button type="submit" class="uppercase mt-2 h-16 text-xl font-bold tracking-wide bg-accent text-gray-100 p-3 rounded-lg w-full transition duration-300 hover:opacity-80 cursor-pointer" > Upload </button> </div> </form> </div> </div> </template> <script> import "vue-select/dist/vue-select.css"; export default { name: "fileUpload", middleware: "auth", props: [ "file", "type", "category", "parentDesignCategory", "parentDesignType" ], data() { return { designCategory: this.parentDesignCategory, designType: this.parentDesignType, designLikes: null }; }, computed: { imageSrc: function() { return URL.createObjectURL(this.file); } }, created() {}, methods: { async uploadImage() { let formData = new FormData(); const config = { headers: { "content-type": "multipart/form-data" } }; formData.append("likes", this.designLikes); formData.append("image", this.file); formData.append("category", this.designCategory); formData.append("type", this.designType); await this.$axios .post("upload", formData, config) .then(response => { this.progress = 0; this.showToast("Photo Uploaded.", "success"); // Delete coomponent when upload complete this.$emit("delete-row"); }) .catch(error => { }); }, removeSelf: function() { this.$emit("delete-row"); }); } } }; </script>
Now my first and main problem is when the user removes the component from the dom, it removes the component but the Selected category/type stays in the same position. Suppose I chose 4 images. I set 2nd image category as “a”. When I remove 1st image. 1st image gets removed and 2nd image comes at 1st place but the category selected “a” remains on position 2.
Now 2nd problem is if I chose the category for the universal component in the parent page before selecting images it applies to all components. but after selecting images, Universal select doesn’t work.
3rd problem is transition doesn’t work on any component.
Advertisement
Answer
Simple answer is – you have to set an unique ID
. Here is how you can solve that:
Changings in the template:
First of all you need to set an id
instead of using your index
– setting an id
makes it unique and that is what we need. So set your :key
to file.id
(we will create it in the script) and pass your file
with deleteThisRow
to your methods. Done!
<div class="md:w-1/2" v-for="file in files" :key="file.id"> //and change your index here to file here we will reference on the unique file we will create with the unique id we will set @delete-row="deleteThisRow(file)"
Changings in the script: Set your id = null
in data()
– that your created id will not be undefined. After that go to your methods
and set your id = i
– now it’s unique and could not be change anymore like your index
could. Last thing you should do is to map
over your files array
and get the correct index
which should be deleted with indexOf
.
//in your data data() { return { id: null, } }, //in your methods methods: { uploadImage(event) { let file = event.target.files; for (let i = 0; i < file.length; i++) { this.files.push({image:file[i], id : i}); //here you set your id to an unique number! (could be this.id you have to try) } }, deleteThisRow: function(file) { var indexDelete = this.files.map(x => { return x.id; }).indexOf(file.id); this.files.splice(indexDelete, 1); } }
After all you have to pass your file.id
to your child with following code:
<child :uniqueID="file.id" :file="file.image">
and reference
on this in your child with props
Hopefully I understood your question correct – than that should work out for your problem – please let me know if this works for you !
Additional Info: Please change all index
-values to file.id
– than everything is really unique
.