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:

  1. Watcher must be added every time new field is added
  2. You should probably store return value of watch to stop the watcher when the field is removed
  3. As elements of the fields array are reactive objects and not refs, the overload of watch 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)
      }
    }