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
Subject
with the sameid
but differentname
, you will be editing thatname
in the list. - If you edit the
Subject
that you've added to the array. When you change itsid
, if theid
that 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>