Skip to content
Snippets Groups Projects
Autocomplete.vue 3.89 KiB
<template>
  <div class="autocomplete-container" :class="$vuetify.breakpoint.name">
    <v-combobox accesskey="s" aria-label="søkefelt"
        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', allowOverflow: true}"
        prepend-inner-icon="search"
        :append-icon="null"
        return-object
        rounded
        hide-no-data
        auto-select-first
        no-filter
        hide-details
        label="Søk..."
        solo
        full-width
        flat
        outlined
        placeholder="Søk her"
        ref="autocomplete"
        color="primary"
        :dense="$vuetify.breakpoint.smAndDown"
      >
      <template v-slot:item="data">
      <span class="search-hit">
        {{data.item.label}}
      </span>
      ({{data.item.lang? data.item.lang[1] ? "bm, nn" : {"bob": "bm", "nob": "nn"}[data.item.lang[0]] : 'fritekstsøk'}})
      </template>
    </v-combobox>
  </div>
</template>

<script>

  export default {
    props: {
      api: Function,
    },
    data: function() {
      return {
        loading: false,
        items: [],
        search: null,
        select: null,
        suggesting: null,
      }
    },
    watch: {
      search (val) {
        const time = Date.now()
        if (! val) {
          this.items = []
        } else {
          this.run_query(val, time)
        }
      },
      select(item) {
        if (item) {
          if (typeof item != 'string') {
            this.items = []
            this.suggesting = false
            if (item.article_promise) {
              item.article_promise.then((response) => {
                item.article_ids =  response.data
                this.submit(item)
              })
            }
            else {
              this.submit(item)
              }
          }
          // If blurred
          else {
            this.items = []
          }
        }
      }
    },
    methods: {
      run_query(q, time) {
        this.suggesting = true
        // Keep full text search in the list while requesting suggestions
        if (this.items[0]) {
          if (this.items[0].time < time) {
            this.items.splice(0,1, {q: q, label: q, time: time})
          }
        }
        else {
          this.items.push({q: q, label: q, time: time})
        }
        let self = this
        self.api.get('suggest?', {params: {q: q, dict: self.$parent.lang, n: 9}})
            .then(async (response) => {
                        if (self.$refs.autocomplete.searchInput == q & self.suggesting) {

                          let hits = []
                          response.data.forEach((item, i) => {
                            let match = item[0]
                            let hit = {q: q, match: match, label: match, time: time}

                            hit.article_promise = self.api.get('articles?', {params: {lord: match, dict: self.$parent.lang}})

                            hit.lang = item[1]
                            hits.push(hit)

                          });
                          // whitespace necessary because duplicates aren't allowed in the dropdown
                          hits.push({q: q, label: q + ' ', time: time})
                          self.items = hits
                        }
                      self.loading = false
                    })

      },
      submit(item) {

          this.$emit('submit', item)
          let self = this

          setTimeout(() => {
          self.$refs.autocomplete.$refs.input.select()
          this.items = []
          this.suggesting = false
          }, 1)

      }
    },
  }
</script>


<style scoped>
  .search-hit {
    font-weight: bold;
    margin-right: 5px;
    color: var(--v-primary-base);
  }

  .autocomplete-container {
    padding-left: 10px;
    padding-right: 10px;
  }
</style>