quasar icon indicating copy to clipboard operation
quasar copied to clipboard

QSelect with Basic Filtering example does not reset input when clicking in no-option slot and then losing focus

Open vincemammoliti opened this issue 2 years ago • 10 comments
trafficstars

What happened?

Using the "Basic Filtering" example from the docs (https://quasar.dev/vue-components/select#filtering-and-autocomplete), when I filter for a value that isn't in the list it shows the no-option slot (i.e. "No results") . If I click the "No results" and then click outside the element, the input keeps the invalid value.

What did you expect to happen?

The input should restore to the previously selected item, or blank.

Reproduction URL

https://quasar.dev/vue-components/select#filtering-and-autocomplete

How to reproduce?

  1. Click in the QSelect input
  2. Type "abc"
  3. Click "No results"
  4. Click outside of the QSelect component

Flavour

Vite Plugin (@quasar/vite-plugin)

Areas

Components (quasar)

Platforms/Browsers

Chrome

Quasar info output

No response

Relevant log output

No response

Additional context

No response

vincemammoliti avatar Aug 02 '23 04:08 vincemammoliti

Hi @vincemammoliti! 👋

It looks like you provided an invalid or unsupported reproduction URL. Do not use any service other than Codepen, jsFiddle, StackBlitz, Codesandbox, and GitHub. Make sure the URL you provided is correct and reachable. You can test it by visiting it in a private tab, another device, etc. Please edit your original post above and provide a valid reproduction URL as explained.

Without a proper reproduction, your issue will have to get closed.

Thank you for your collaboration. 👏

github-actions[bot] avatar Aug 02 '23 04:08 github-actions[bot]

It was not supposed to do that. There is nowhere any mention that it works like that.

pdanpdan avatar Aug 02 '23 04:08 pdanpdan

It was not supposed to do that. There is nowhere any mention that it works like that.

My expectation of what should happen is what the component already does when, for example, you tab out of the select input, or you click outside of the select input.

To clarify, the issue is only when you first click on the "No results" (no-option slot) and then click outside of the select input.

Here is a recording of how the QSelect component works correctly when you have an invalid filter string and then click outside the component. Notice how the "abc" string in the input is cleared/reset. invalid option expectation (regular click outside)

Here is a recording of how the Qselect component has an issue when you have an invalid filter string and first click on "No results" and then click outside the component. Notice how the "abc" string in the input is not cleared. invalid option issue (first click no results then click outside)

Please review again and it would be appreciated if you could re-open the issue. Thanks

vincemammoliti avatar Aug 02 '23 23:08 vincemammoliti

The content of the slot is not designed as an option. It does nothing on click by default

pdanpdan avatar Aug 02 '23 23:08 pdanpdan

I understand that, but I think you're missing my point. I'm not expecting that clicking "No results" would clear my input. I'm expecting that when I lose focus on the input, if the filter string is invalid, then the input should be cleared.

As I demonstrated above, QSelect already clears the input when you tab out of the component or when you click outside of the component. So the expectation is it should also work that same way whichever way you make the component lose focus. But, the bug is if you first click in "No results" and then click outside the component, the input value does not get cleared/reset.

Please try to reproduce and I'm sure you will understand.

From a user's perspective, if the input is not cleared/reset when they input an invalid option/filter string, then it appears as if the value they entered is valid and will be saved with the form submission, when in fact the underlying model-value is actually not "abc" in this case.

Side note; I've made a work around for now by resetting the input value onPopupHide event if there are no filtered options.

vincemammoliti avatar Aug 03 '23 00:08 vincemammoliti

Ah, now I understand. Sorry for missing the problem.

pdanpdan avatar Aug 03 '23 00:08 pdanpdan

This is a duplicate of https://github.com/quasarframework/quasar/issues/16135 right?

nielsswinkels avatar Sep 18 '23 13:09 nielsswinkels

Good catch :D

pdanpdan avatar Sep 18 '23 13:09 pdanpdan

Has anyone solved the problem yet?

billsoftltd avatar May 15 '25 05:05 billsoftltd

Has anyone solved the problem yet?

It's a work around, but what I landed on is to:

  • clearInputWhenInvalid when the blur event is emitted from the QSelect component.
  • clearModelWhenEmpty when the input-value event is emitted from the QSelect component.

Extending upon the "Basic Filtering" example from the docs (https://quasar.dev/vue-components/select#example--basic-filtering), this is what my solution would look like:

<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row">
      <q-select
        ref="select"
        filled
        v-model="model"
        use-input
        hide-selected
        fill-input
        input-debounce="0"
        :options="options"
        @filter="filterFn"
        hint="Basic filtering"
        style="width: 250px; padding-bottom: 32px"
        @blur="clearInputWhenInvalid"
        @input-value="clearModelWhenEmpty"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const stringOptions = [
'Google', 'Facebook', 'Twitter', 'Apple', 'Oracle'
]

const options = ref(stringOptions)

const model = ref(null)

function filterFn(val, update, abort) {
  update(() => {
    const needle = val.toLowerCase()
    options.value = stringOptions.filter(v => v.toLowerCase().indexOf(needle) > -1)
  })
}

// Extending beyond the "Basic Filtering" example from the docs starts below...

const select = ref(null)

const inputElement = computed(() => {
  return select.value.$el.getElementsByTagName('input')[0]
})

function clearInputWhenInvalid() {
  if (!options.value.includes(inputElement.value.value)) {
    select.value.updateInputValue('', true)
  }
}

function clearModelWhenEmpty(value) {
  if (value === null || value === undefined || value.trim() === '') {
    model.value = null
  }
}
</script>

vincemammoliti avatar May 15 '25 11:05 vincemammoliti