The requirement is to rename the files before uploading it to the system. So I tired using v-model but failed. So I came up with the following which is working great just that I cannot retain my input text value. The preventdefault
isn't working.
Here I uploaded 3 images and rename them as First, Second and Third.
<div>
<input type="file" @change="addFile" multiple>Choose file
</div>
<div v-if="selectedFiles && selectedFiles.length>0">
<div v-for="(item, index) in selectedFiles">
<span>{{ item.name }}</span>
<input type="text" v-model="" placeholder="Rename File" @change="renameFile(item,event)"/>
<button @click="removeFile(event,item,index)"></button>
</div>
</div>
<button @click="uploadDrawings">Upload Files</button>
data: {
selectedFiles: [],
renameFiles: [],
finalFiles: [],
},
methods: {
addFile(event) {
_.each(Array.from(event.target.files), function (file) {
var existed = _.find(app.selectedFiles, function (item) {
return item.name == file.name;
});
if (!existed) {
app.selectedFiles.push(file);
}
});
},
renameFile(item, event) {
if (app.renameFiles.filter(x => x.oldName == item.name).length > 0) {
var objIndex = app.renameFiles.findIndex(x => x.oldName == item.name);
app.renameFiles[objIndex].newName = event.target.value;
}
else {
app.renameFiles.push({
oldName: item.name,
newName: event.target.value
})
}
},
removeFile(e,item, index) {
e.preventDefault(); // while removing an item, the text value changes.
app.selectedFiles.splice(index, 1);
var objIndex = app.renameFiles.findIndex(x => x.oldName == item.name);
app.renameFiles.splice(objIndex, 1);
},
uploadDrawings() {
app.isLoading = true;
if (app.selectedFiles.length == 0) {
return;
}
_.each(app.selectedFiles, function (item) {
var blob = item.slice(0, item.size, 'image/jpg');
var name = app.renameFiles.filter(x => x.oldName == item.name);
app.finalFiles.push(new File([blob], name[0].newName '.jpeg', { type: 'image/jpg' }));
});
}
So, On removing item from top to bottom the text box does not retain its value. First
was assigned for 091646
.
However, the finalFiles
has the correct naming files. Its just the textbox which has a problem.
Please help me to retain the textbox values. Thanks in advance.
CodePudding user response:
Missing key
s
The items in the v-for
are not explicitly keyed in your markup, so Vue automatically keys them by their index. As a rendering optimization, Vue reuses existing elements identified by their keys. This can cause an issue when an item is added to or removed from the middle of the list, where surrounding items take on new keys equal to their new indices.
Solution
Apply the key
attribute to each v-for
item using a unique ID (not equal to index
). In this case, the index
combined with the filename would suffice:
<div v-for="(item, index) in selectedFiles" :key="index item.name">
Missing v-model
s
When the template is re-rendered (occurs when removing an item from the middle of the list), the textboxes lose their values. This is because they have no model bound to them.
Solution
Update renameFiles[]
to store only strings (instead of objects), where each string corresponds to a file in selectedFiles[]
by the same index. That would obviate the file lookup code throughout your methods, so the code would be simplified to this:
export default {
⋮
methods: {
addFile(event) {
this.selectedFiles = Array.from(event.target.files)
},
removeFile(e, item, index) {
this.selectedFiles.splice(index, 1)
this.renameFiles.splice(index, 1)
},
⋮
},
}
That change also enables using renameFiles[]
as v-model
on the <input>
s for the rename strings:
<input type="text" v-model="renameFiles[index]" placeholder="Rename File" />