vuejs3quasar-framework

Expand a Quasar q-expansion-item if a nested input fails validation?


I have a series of q-expansion-items each of which contains a group of inputs, all part of a single overall form:

<q-form @validation-error="onValidationError">
 <q-expansion-item>
  <field-group-1 />
 </q-expansion-item>
 <q-expansion-item>
  <field-group-2 />
 </q-expansion-item>
 ...
</q-form>

The inputs use rules-based validation, and I'm calling validate on the form before proceeding.

This works, but if the invalid input is inside a closed q-expansion-item the user doesn't have any way of knowing which input failed. I'd like to trigger the relevant q-expansion-item to show itself in this case.

Right now I'm using a super hacky approach, which works but is really fragile -- I'm catching the failing input then walking up the component hierarchy until I identify the q-expansion-item via duck typing:

function onValidationError(ref: any) {
  let parent = ref.$parent;
  while (parent && !parent.show) {
    parent = parent.$parent;
  }
  if (parent?.show) {
    parent.show();
  }
}

Is there a better way to do this?


Solution

  • A ref based solution would be a more Vue-centric approach. It's not too dissimilar and still involves a loop but I think a less fragile one.

    Add refs to expansion items:

    <q-form @validation-error="onValidationError">
     <q-expansion-item ref="group1">
      <field-group-1 />
     </q-expansion-item>
     <q-expansion-item ref="group2">
      <field-group-2 />
     </q-expansion-item>
     ...
    </q-form>
    

    Use for loop to find if any expansion-item ref contains the invalid component

    const group1 = ref()
    const group2 = ref()
    
    onValidationError(invalidComp) {
      const expansionRefs = [group1, group2];
    
      for (const expansionItem of expansionRefs) {
        if (expansionItem.value.$el?.contains?.(invalidComp.$el)) {
          expansionItem.value.show();
          break;
        }
      }
    }