darrenjennings / vue-autosuggest

🔍 Vue autosuggest component.
https://darrenjennings.github.io/vue-autosuggest
MIT License
621 stars 91 forks source link

[How to] Programmatically select the first suggestion on tab or blur from input #94

Closed mmccaff closed 5 years ago

mmccaff commented 5 years ago

Description:

Sorry, this is likely not a bug, but I am having some trouble doing something with the component.

I'm trying to automatically select the first suggestion on a blur or tab event from the input, so that the input element is given a value, the suggestions dialog is closed, and the selected variable is set to the first suggestion object -- as if the first item were clicked. (I'd only do this if a value was not chosen/assigned.)

The use case is: typing in three letters, then immediate tabbing out without selecting a suggestion, should act as if the first suggestion were clicked.

What is the recommended way to do this? I can call setChangeItem using a ref, but it does not change the input value. I can set searchInput using a ref, but that triggers a change and does another lookup leaving a new dropdown opened. I thought I might even try triggering a click on the first element, but that's not going to work either.

Similarly, a second but related issue I'm having - when backspacing to delete all characters of the input, I'd like to make the value and selected object be empty. It's not, so vee-validate will still see the field as non-empty after erasing all input from it after previously having a selection.

How can I automate selecting a suggestion when there are suggestions, as if it were clicked? How can I fully "reset" a selection to a blank slate?

Relevant code or config:


// attributes on vue-autosuggest
ref="autosuggest"
@blur="blurHandler"
@keydown.tab="tabHandler"

.
.

// snippets from methods

// trying to "reset" selected (& value, but not sure how) when there are no suggestions
fetchResults(val) {
if (!val || (val.length < 2)) {
  this.suggestions = [];
  this.selected = null;
  return;
}
.
.
.

}

// trying to auto-select the first suggestion three different ways
tabHandler(e) {
/*
let item = this.$refs.autosuggest.getItemByIndex(0);
this.$refs.autosuggest.setChangeItem(item, true);
this.suggestions = [];
*/

/*
const element = this.$el.querySelector('#autosuggest__results_item-0');               
element.click();
*/          

/*
let item = this.$refs.autosuggest.getItemByIndex(0);
this.$refs.autosuggest.searchInput = item;
*/
},

Any advice here would be very much appreciated! Thanks for the component. :)

darrenjennings commented 5 years ago

version 2.0 currently in beta will hopefully make working with veevalidate easier. I still need to be test it but switching to v-model will help since it will emit an input event. In 1.8 I believe you can just clear searchInput $refs.autosuggest.searchInput = '', but haven't worked with veevalidate enough to know.

To address your first point, you can do something like this:

<vue-autosuggest
  ref="autosuggest"
  @keydown.tab.prevent="tabHandler"
tabHandler(){
  this.$refs.autosuggest.setCurrentIndex(0)
},

Demo: https://codesandbox.io/s/627qlx66oz?from-embed

mmccaff commented 5 years ago

Thank you for the suggestion. However, setting the index, as shown in the demo, only sets the active item by highlighting it. I’d like to be able to programmatically choose that selected item as if it were clicked on with a mouse or the enter key were pressed. I am trying to choose the first suggestion on a tab or blur, not just highlight it; setting the state of everything as if it were clicked on. So, if I typed “git” and then tab, and the first suggestion were GitHub, it’d be as if GitHub were selected by clicking on it.

Is that possible? To choose the first suggestion programmatically?

On Feb 21, 2019, at 12:13 AM, Darren Jennings notifications@github.com wrote:

version 2.0 currently in beta will hopefully make working with veevalidate easier. I still need to be test it but switching to v-model will help since it will emit an input event. In 1.8 I believe you can just clear searchInput $refs.autosuggest.searchInput = '', but haven't worked with veevalidate enough to know.

To address your first point, you can do something like this:

<vue-autosuggest ref="autosuggest" @keydown.tab.prevent="tabHandler" tabHandler(){ this.$refs.autosuggest.setCurrentIndex(0) }, Demo: https://codesandbox.io/s/627qlx66oz?from-embed

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

darrenjennings commented 5 years ago

ah yes I thought you'd want to tab then hit enter to select. This is not ideal, but here's the solution. I will make sure 2.0 I'm currently iterating on has something a bit more ergonomic. Open to suggestions.

tabHandler(){
  const { listeners, setCurrentIndex, setChangeItem, getItemByIndex } = this.$refs.autosuggest

  setCurrentIndex(0)
  setChangeItem(getItemByIndex(this.$refs.autosuggest.currentIndex), true)
  this.$refs.autosuggest.loading = true
  listeners.selected(true)
},

Updated the codesandbox.

mmccaff commented 5 years ago

Yes! This is what I was looking for. I was close, but missing the listeners.selected(true).

Thanks for considering this case for v2.

ghost commented 5 years ago

Hi, is it possible to apply this on mounted() hook?

I'm trying to pass an InitialValue but currently it displays suggestions, I want to apply the mentioned code so that it sets the first suggestion as "selected".

Problem is on mounted() hook I get "undefined" for this.$refs.autosuggest.