Firing watcher on dynamic fields
I have a vue app using Quasar that loads a modal to perform a function once an image is selected. This works for a fixed value, but I cannot get it to work for a field that is created dynamically (meaning that the user can add them by clicking an "add field" button).
Problems I want to create one watcher that fires on each of the three fields (imgOne, imgTwo, and imgThree). I can get it to fire on the change of the array using the deep modifier, but that doesn't work for my purposes.
Bonus Problem: How to permit the file input field to be clearable without triggering watch.
<q-file
v-model="map"
label="map"
></q-file>
<div
v-for="(field, i) in fields"
:key="i"
>
<q-file
v-model="fields[i].imgOne"
></q-file>
<q-file
v-model="fields[i].imgTwo"
></q-file>
<q-file
v-model="fields[i].imgThree"
></q-file>
</div>
watch(map, (currentValue, oldValue) => {
//this works to launch the modal
});
watch(
fields.imgOne,
(currentValue, oldValue) => {
//this does not work. I cannot use fields[i].imgOne or
//fields.value.imgOne
//I want this to fire each time imgOne, imgTwo, or
//imgThree change
},
{ deep: true }
);
Solution 1:
Maintaining individual watcher for each entry in fields
array (or 3 watchers if you want separate watcher for imgOne
, imgTwo
etc. - not clear from the question) is definitely possible but you need to fix few things:
- Watcher must be added every time new field is added
- You should probably store return value of
watch
to stop the watcher when the field is removed - As elements of the
fields
array are reactive objects and notref
s, the overload ofwatch
receiving function must be used
// after new field with index addedFieldIndex is added into array
// local variable
const addedFieldIndex = XX
const field = fields[addedFieldIndex]
field.watcher = watch(
// watching multiple sources at once
[
() => field.imgOne,
() => field.imgTwo,
() => field.imgThree
], handler)
Anyway this is absolutely unnecessary and complicated. watch
is not best tool in this situation imho. Much better tool is an update:model-value
event (same event used by v-model
) that is fired when the file is selected or cleared
<q-file
v-model="fields[i].imgThree"
@update:model-value="onFileSelected(field, $event)"
></q-file>
const onFileSelected = (field, fileSelected) => {
// null is used when field is cleared
if(fileSelected !== null) {
console.log("File ", fileSelected, " for field ", field.id)
}
}