afcapel / stimulus-autocomplete

Stimulus autocomplete component
MIT License
478 stars 61 forks source link

How to fetch data on focus? #110

Closed arrowcircle closed 2 years ago

arrowcircle commented 2 years ago

Hey! Nice lib, thanks for the great work! I am struggling to open prompt with results as soon, as user focused input field. I tried to add

autocomplete-min-length-value="0"

but this does not help.

How can I fetch data as soon, as user sets focus into input?

coderifous commented 2 years ago

@arrowcircle I believe I had the same goal as you, and attempted the same approach - with the same results. Here is the workaround that (mostly) worked for me:

I added this to the input element: data-action="click->autocomplete#fetchResults"

I tried using focus, i.e. data-action="focus->autocomplete#fetchResults", but that didn't work for me (not sure why), but this trade off where the user will need to click on the input field works for my use-case.

Not 100%, but fairly low effort. :shrug:

Good luck!

afcapel commented 2 years ago

I tried using focus, i.e. data-action="focus->autocomplete#fetchResults", but that didn't work for me (not sure why)

That's probably because the focus event doesn't bubble. It should work with focusin.

coderifous commented 2 years ago

Thanks @afcapel - duh on my part.

In case anyone ever stumbles upon this thread, here's the incantation that worked for me in the end: data-action="focusin->autocomplete#fetchResults:once focusout->autocomplete#close:once"

elalemanyo commented 1 year ago

@coderifous I was trying to use your solution but if we add focusout we lose click selection 😔

https://user-images.githubusercontent.com/3856862/196664794-55be113c-6e64-4b34-9308-289723154ebc.mp4

Did you found a workaround?

arrowcircle commented 1 year ago

Stupid question, but which element should include this "data-action" => "focusin->autocomplete#fetchResults:once focusout->autocomplete#close:once" ?

elalemanyo commented 1 year ago

Stupid question, but which element should include this "data-action" => "focusin->autocomplete#fetchResults:once focusout->autocomplete#close:once" ?

@arrowcircle the input where you set data-autocomplete-target="input"

arrowcircle commented 1 year ago

@arrowcircle the input where you set data-autocomplete-target="input"

Somehow it does not work. I have this haml, but autocomplete fires only after entering something:

.mb-4{"data-autocomplete-url-value" => search_artists_path, "autocomplete-min-length-value" => 0, "data-controller" => "autocomplete", id: "artist_search"}
  = f.text_field :artist_name, data: { "autocomplete-target" => :input, "action" => "focusin->autocomplete#fetchResults:once focusout->autocomplete#close:once" }, class: input_classes, placeholder: "Name"
  = f.hidden_field :artist_id, data: { "autocomplete-target" => :hidden }

What I am doing wrong?

elalemanyo commented 1 year ago
<div class="mb-3">
  <label for="birds">Plain text bird names</label>
  <div data-controller="autocomplete" data-autocomplete-url-value="/results-plain-text.html">
    <input name="birds" type="text" class="form-control" data-autocomplete-target="input" placeholder="search a bird" data-action="focusin->autocomplete#fetchResults focusout->autocomplete#close"/>
    <input type="hidden" name="bird_id" data-autocomplete-target="hidden"/>
    <ul data-autocomplete-target="results" class="list-group"></ul>
  </div>
</div>

@arrowcircle can you try this?

ACPK commented 1 year ago

@arrowcircle The code above from @coderifous also doesn't work for me. If I click off the search bar and then come back, the results show up for me at first. If I try to do it again, it doesn't work even though the search input field is still filled in.

elalemanyo commented 1 year ago

@ACPK can you try my pr, I have been using it for some time now and I think it works quite well.

Simonpedro commented 1 year ago

For those having the same issue, I worked around it by extending the exported controller and overriding the onInputChange. I created this PR with the fix I used.

For now, try registering the following controller instead of the one exported by default:

import BaseAutocompleteController from "stimulus-autocomplete"

export default class AutocompleteController extends BaseAutocompleteController {
  /**
   * We override the default stimulus-autocomplete behavior to allow fetching
   * results when query is ''. Useful for fetching data on focus.
   * 
   * There are two opened PRs to add this functionality to stimulus-autocomplete:
   * - https://github.com/afcapel/stimulus-autocomplete/pull/138
   * - https://github.com/afcapel/stimulus-autocomplete/pull/121
   * 
   * Whenever any of those PRs is merged, we may want to remove this override.
   */
  onInputChange = (): void => {
    if (this.hasHiddenTarget) this.hiddenTarget.value = ""
    const query = this.inputTarget.value.trim()

    if (query.length >= this.minLengthValue) {
      this.fetchResults(query)
    } else {
      this.hideAndRemoveOptions()
    }
  }
}

and then in the html you can do something like:

<input
  name="search"
  data-autocomplete-target="input"
  data-autocomplete-url-value="/search?q={q}"
  data-autocomplete-min-length-value="0"
  data-action="focusin->autocomplete#onInputChange"
/>