Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update method firing when input field blurs #50

Open
bencarter78 opened this issue May 8, 2017 · 1 comment
Open

Update method firing when input field blurs #50

bencarter78 opened this issue May 8, 2017 · 1 comment

Comments

@bencarter78
Copy link

bencarter78 commented May 8, 2017

Hi there

First off, thanks for making a great package! 👍

I'm doing a Vue 1 -> Vue 2 upgrade and I'm coming across an issue where by when I search for a resource, I can select it from the dropdown that appears, it populates the input field but when I exit the field it makes another request and the dropdown appears again.

It seems that it the update method is being fired when I leave the input field. Any ideas what I could be doing wrong?

<template>
    <div>
        <input :name="fieldName + '_id'" type="hidden" v-bind:value="fieldNameId">

        <input :id="fieldName"
               :name="fieldName"
               type="text"
               class="form-control"
               placeholder="Search..."
               autocomplete="off"
               v-model="query"
               @keydown.down="down"
               @keydown.up="up"
               @keydown.enter.prevent
               @keydown.enter="hit"
               @keydown.esc="reset"
               @input="update"/>

        <div id="autocomplete-results" v-if="hasItems">
            <ul class="list-group results">
                <li class="list-group-item results-item" v-for="(item, index) in items" :class="activeClass(index)" @mousedown="hit" @mousemove="setActive(index)">
                   {{ item.display }}
                </li>
            </ul>
        </div>
    </div>
</template>

<script>
    import VueTypeahead from 'vue-typeahead'

    export default {
        extends: VueTypeahead,

        props: ['fieldName', 'value', 'endpoint', 'attributes', 'relationships'],

        data () {
            return {
                query: '',
                src: this.endpoint,
                limit: 5,
                minChars: 3,
                queryParamName: 'q',
                fieldNameId: ''
            }
        },

        mounted () {
            this.query = this.value
        },

        methods: {
            prepareResponseData (items) {
                for (let i = 0; i < items.length; i++) {
                    var fields = this.transformAttributes(items[i])
                    var relationships = this.transformRelationships(items[i])
                    items[i].display = fields + ' - ' + relationships
                }
                return items
            },

            transformAttributes (item) {
                let q = []
                for (let i = 0; i < this.attributes.length; i++) {
                    q.push(item[this.attributes[i]])
                }
                return q.join(' ')
            },

            transformRelationships (item) {
                let r = []
                for (let [key, value] of Object.entries(this.relationships)) {
                    if (this.relationships.hasOwnProperty(key)) {
                        for (let data of item[key]) {
                            r.push(data[value])
                        }
                    }
                }
                return r.join(', ')
            },

            onHit (item) {
                console.log(item)
                this.query = this.transformAttributes(item)
                this.fieldNameId = item.id
                this.value = this.query
                this.items = []
            },

            isValid () {
                if (this.value != this.query) {
                    this.fieldNameId = ''
                }
            }
        }
    }
</script>
@cgs
Copy link

cgs commented May 16, 2017

@bencarter78 Scratched my head on this one for some time. Here's what worked:

export default {
  extends: VueTypeahead,
  data () {
    return {
      src: '/guided_search/keyword_search',
      limit: 5,
      minChars: 3,
      showItems: true // for some reason, directly manipulating the items array is buggy; i.e. items = [] is not reliable
    }
  },
  methods: {
    doUpdate(event) {
      this.showItems = true
      this.update()
    },
    onHit(item) {
      this.query = item
      $("input[name='disease']").val(this.query) // firefox needs this ¯\_(ツ)_/¯
      this.softReset()
    },
    softReset() {
      this.loading = false
      this.showItems = false
    }
  }
}

and in the template:

<input type="text"
   name="disease"
    :class="{'Typeahead__input': true}"
    placeholder="Example: Leukemia"
    autocomplete="off"
    v-model="query"
    v-validate="'required'"           
    @keydown.down="down"
    @keydown.up="up"
    @keydown.enter="hit"
    @keydown.esc="reset"
    @blur="softReset"
    @input="doUpdate"/>

<ul v-show="hasItems && showItems">
...
</ul>

In my case I wanted the query to stay in the input on blur, even if no results matched. Clearing out the items via items = [] was giving me mixed results. I would type 3 characters (the default to trigger the data to load) and according to the Chrome vue inspector, I could see the items var get populated with a few results. In softReset() I was calling items = []. Logging that in the console, items was empty. However, in the vue inspector it was still populated and the dropdown with options was still appearing. Not sure what's going on there; something with data and extends maybe? I ended up adding showItems to data as a workaround.

It would be nice to have a "selecting item populates the input box" as a core feature as this is a pretty common use case. Would be happy to submit a pull req, but my solution above is a bit hacky and I'm stumped why manipulating the items array isn't working.

I should also mention that this does not fix the update event from firing on blur - this could be the expected Vue behavior, but I'm not certain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants