I am creating a website for planning out study timetables.
I am now creating an Add/Remove subject section where user can add, edit or remove the Subject containing id and name, all the subjects user have added will be represented as a list of <input>s so users can easily edit them, and stored as an array of objects (Array<{ id: string, name: string }>).
I have some criteria that I wanted the list to behave when user edits the key (subject ID) whether the added one or the one they're adding.
- If you add new
Subjectwith the sameidbut differentname, you will be editing thatnamein the list. - If you edit the
Subjectthat you've added to the array. When you change itsid, if theidthat you've changed is the same as the other one, the old one will get deleted. for example.
const subjectList = [
{ id: 'B2205', name: 'Business 1' },
{ id: 'B2210', name: 'Internship' },
{ id: 'U1539', name: 'Undergraduate Thesis' }
]
// User edits the id from B2210 to B2205, the array will become
const subjectList = [
{ id: 'B2205', name: 'Internship' },
{ id: 'U1539', name: 'Undergraduate Thesis' }
]
The problem that I am having is that I am trying to implement a feature where on the second criteria. When the id is changed and the duplicate is deleted. I wanted to call HTMLInputElement.focus() on the <input> so users can continue editing without leaving the keyboard.
I approached the problem by using Template Refs with v-for. I created 2 variables called subjects storing Subject object that users have created, and subjectRefs to act as reference to each <input> that I'm going to generate using v-for. This solution works as expected when adding new subject. but when I delete the subject. value in subjects gets deleted but in subjectRefs, it does not get deleted. It stays the same length as before. I logged out the value and sees this.
// Initial
subjects | subjectRefs
[] []
// Add { id: 'A1', name: 'A' }
subjects | subjectRefs
[ | [
{ id: 'A1', name: 'A' } | HTMLInputElement.value = 'A1'
]
| ]
// Add { id: 'B1', name: 'B' }
subjects | subjectRefs
[ | [
{ id: 'A1', name: 'A' } | HTMLInputElement.value = 'A1'
{ id: 'B1', name: 'B' } | HTMlInputElement.value = 'B1'
] | ]
// Remove { id: 'B1', name: 'B' }
subjects | subjectRefs
[ | [
{ id: 'A1', name: 'A' } | HTMLInputElement.value = 'A1'
] | HTMlInputElement.value = 'B1'
| ]
// Add { id: 'C1', name: 'C' }
subjects | subjectRefs
[ | [
{ id: 'A1', name: 'A' } | HTMLInputElement.value = 'A1'
{ id: 'C1', name: 'C' } | HTMlInputElement.value = 'C1'
] | ]
// Remove { id: 'A1', name: 'A' }
subjects | subjectRefs
[ | [
{ id: 'C1', name: 'C' } | HTMLInputElement.value = 'C1'
] | HTMlInputElement.value = 'C1'
| ]
// Add { id: 'A1', name: 'A' } and { id: 'B2', name: 'B' }
subjects | subjectRefs
[ | [
{ id: 'C1', name: 'C' } | HTMLInputElement.value = 'C1'
{ id: 'A1', name: 'A' } | HTMlInputElement.value = 'A1'
{ id: 'B2', name: 'B' } | HTMLInputElement.value = 'B2'
] | ]
// Edit { id: 'C1', name: 'C' } to { id: 'C9', name: 'C' }
subjects | subjectRefs
[ | [
{ id: 'C9', name: 'C' } | HTMLInputElement.value = 'C9'
{ id: 'A1', name: 'A' } | HTMlInputElement.value = 'A1'
{ id: 'B2', name: 'B' } | HTMLInputElement.value = 'B2'
] | ]
// Remove { id: 'C9', name: 'C' } and { id: 'A1', name: 'A' }
subjects | subjectRefs
[ | [
{ id: 'B2', name: 'B' } | HTMLInputElement.value = 'B2'
] | HTMlInputElement.value = 'B2'
| HTMLInputElement.value = 'B2'
| ]
It doesn't look like the subjectRefs are updating its value, I don't know if manually manipulating the ref array will be bad thing or not.
I have provided a codesandbox for you guys here but the logs won't let you see that deep. If you have any more questions or requirements please let me know. Thank you.
CodePudding user response:
Probably you can change your removeSubject function like this i.e add code to remove from subjectRefs as well
const removeSubject = (index) => {
try {
subjects.value.splice(index, 1);
subjectRefs.value.splice(index, 1);
} catch (e) {
throw new Error("Cannot convert 'key' to number.");
}
console.log(subjects.value, subjectRefs.value);
};
I guess you were expecting that it would be automatically removed on re render, but that doesn't happen in your code. Have a look in comments in your code below
<div
v-else
v-for="(subject, i) in subjects" <!--- rerenders everytime subjects changes However vue will not re-render those elements for which key is same -->
:key="`render-subject-${i}`"
>
<input
type="text"
:ref="
(el) => {
if (el != null) subjectRefs[i] = el; <!--- Once set, none of its entry will be deleted unless done manually -->
}
"
:value="subject.id"
@input="editSubject(i, $event?.target.value, 'ID')"
/>
<input
type="text"
:value="subject.name"
@input="editSubject(i, $event?.target.value, 'ID')"
/>
<button @click="removeSubject(i)">
Remove
</button>
</div>
</div>
