Skip to content
Snippets Groups Projects
Autocomplete.vue 4.48 KiB
Newer Older
<template>
  <div class="autocomplete-container" :class="$vuetify.breakpoint.name">
Henrik Askjer's avatar
Henrik Askjer committed
    <v-combobox
Ole Voldsæter's avatar
Ole Voldsæter committed
        v-model="select"
        :loading="loading"
        :items="items"
        :search-input.sync="search"
        item-text="label"
        :menu-props="{maxHeight: $vuetify.breakpoint.name === 'xs' ? 190 : 500, transition: 'fade-transition'}"
Ole Voldsæter's avatar
Ole Voldsæter committed
        prepend-inner-icon="search"
Ole Voldsæter's avatar
Ole Voldsæter committed
        return-object
        rounded
Ole Voldsæter's avatar
Ole Voldsæter committed
        hide-no-data
Henrik Askjer's avatar
Henrik Askjer committed
        auto-select-first
Ole Voldsæter's avatar
Ole Voldsæter committed
        no-filter
        hide-details
        label="Søk..."
        solo
Ole Voldsæter's avatar
Ole Voldsæter committed
        placeholder="Søk her"
Ole Voldsæter's avatar
Ole Voldsæter committed
        ref="autocomplete"
        :dense="$vuetify.breakpoint.smAndDown"
Ole Voldsæter's avatar
Ole Voldsæter committed
      >
      <template v-slot:item="data">
      <span class="search-hit">{{data.item.label}} </span> ({{data.item.lang_set ? Array.from(data.item.lang_set).sort().join(', ') : 'fritekstsøk'}})
      </template>
Henrik Askjer's avatar
Henrik Askjer committed
    </v-combobox>
Ole Voldsæter's avatar
Ole Voldsæter committed
  </div>
</template>

<script>
  import axios from "axios"
  import debounce from "debounce"

  export default {
    props: {
Henrik Askjer's avatar
Henrik Askjer committed
      endpoint: String,
    },
    data: function() {
      return {
        loading: false,
        items: [],
        search: null,
Henrik Askjer's avatar
Henrik Askjer committed
        suggesting: null,
        debounced: debounce(function(q, self) {
          self.loading = true
          return axios.get(self.endpoint + 'suggest?q=' + encodeURIComponent(q))
                      .then(
                            function(response) {
Henrik Askjer's avatar
Henrik Askjer committed
                                if (self.suggesting) {
Henrik Askjer's avatar
Henrik Askjer committed
                                  let hits = []
Henrik Askjer's avatar
Henrik Askjer committed
                                  if (q == self.$refs.autocomplete.searchInput)  {
Henrik Askjer's avatar
Henrik Askjer committed
                                    response.data.forEach((item, i) => {
                                      let match = encodeURIComponent(item.match)
Henrik Askjer's avatar
Henrik Askjer committed
                                      if (! hits[0] || hits[0].word != match) {
                                        hits.splice(0, 0, {q: encodeURIComponent(q), lang_set: new Set(), word: match, articles: []})
                                      }
                                      hits[0].lang_set.add(item.dictionary == 'bob' ? 'bm' : 'nn')
                                      hits[0].articles.push(item)
                                    });
                                    hits.forEach(function (hit) {
                                      if (hit.lang_set) {
                                        hit.label = decodeURIComponent(hit.word)
                                      }
                                    });
                                    hits.reverse()
                                    hits = hits.slice(0, 9)
Henrik Askjer's avatar
Henrik Askjer committed

                                    hits.sort( (h1, h2) => {
Henrik Askjer's avatar
Henrik Askjer committed
                                    let val1 = h1.label.length * 10 + (h1.label[0].toLowerCase() === h1.label[0] ? 0 : 1)
                                    let val2 = h2.label.length * 10 + (h2.label[0].toLowerCase() === h2.label[0] ? 0 : 1)
                                    return val1 - val2
Henrik Askjer's avatar
Henrik Askjer committed
                                  })
Henrik Askjer's avatar
Henrik Askjer committed
                                  let currentSearch = self.$refs.autocomplete.searchInput
                                  if (q == currentSearch) {
                                    self.items = hits
                                  }
                                  self.items.push({currentSearch: encodeURIComponent(currentSearch), label: currentSearch + ' '})
                                  
                                  }
Henrik Askjer's avatar
Henrik Askjer committed
                                }
Henrik Askjer's avatar
Henrik Askjer committed
                                self.loading = false
      }
    },
    watch: {
      search (val) {
        if (! val) {
          this.items = []
        } else {
          this.run_query(val)
        }
Henrik Askjer's avatar
Henrik Askjer committed
        if (item) {
          if (typeof item === 'string') {
            item = {"q": encodeURIComponent(item)}
          }
Henrik Askjer's avatar
Henrik Askjer committed
          this.items = []
          this.suggesting = false

Henrik Askjer's avatar
Henrik Askjer committed
          this.$emit('submit', item)
Henrik Askjer's avatar
Henrik Askjer committed
          setTimeout(() => this.$refs.autocomplete.blur(), 1)
Henrik Askjer's avatar
Henrik Askjer committed
        }
      }
    },
    methods: {
      run_query(q) {
Henrik Askjer's avatar
Henrik Askjer committed
        this.items = []
        this.suggesting = true
        this.debounced(q, this)
<style scoped>
  .search-hit {
    font-weight: bold;
    margin-right: 5px;
    color: var(--v-primary-base);
Ole Voldsæter's avatar
Ole Voldsæter committed

  .autocomplete-container {
</style>