maestro-server/bootue

View on GitHub
src/forms/typeahead/script.js

Summary

Maintainability
A
2 hrs
Test Coverage
import delayer from '../../_core/_utils/delayer.js'
import getJSON from './_utils/getJSON.js'

const DELAY = 300

export default {
  props: {
    async: {type: String},
    data: {type: Array},
    delay: {type: Number, default: DELAY},
    asyncKey: {type: String, default: null},
    limit: {type: Number, default: 8},
    matchCase: {type: Boolean, default: false},
    matchStart: {type: Boolean, default: false},
    onHit: {
      type: Function,
      default: item => item
    },
    onSearch: {
      type: Function,
      default: (url, val) => url + val
    },
    placeholder: {type: String},
    template: {type: String},
    type: {type: String, default: 'text'},
    value: {type: String, default: ''},
    label: {type: String, default: null},
    headers: {type: Array, default: () => []},
    formType: {type: String, default: null},
    horizontalWrapper: {type: String, default: 'col-sm-9'},
    horizontalLabelWrapper: {type: String, default: 'col-sm-3'}
  },
  data () {
    return {
      asign: '',
      showDropdown: false,
      noResults: true,
      current: 0,
      items: [],
      val: this.value
    }
  },
  computed: {
    templateComp () {
      return {
        template: typeof this.template === 'string' ? '<span>' + this.template + '</span>' : '<strong v-html="item"></strong>',
        props: {item: {default: null}}
      }
    }
  },
  watch: {
    val (val, old) {
      this.$emit('input', val)
      if (val !== old && val !== this.asign) this.__update()
    },
    value (val) {
      if (this.val !== val) { this.val = val }
    }
  },
  methods: {
    setItems (data) {
      if (this.async) {
        this.items = this.asyncKey ? data[this.asyncKey] : data
        this.items = this.items.slice(0, this.limit)
      } else {
        this.items = (data || []).filter(value => {
          if (typeof value === 'object') { return true }
          value = this.matchCase ? value : value.toLowerCase()
          let query = this.matchCase ? this.val : this.val.toLowerCase()
          return this.matchStart ? value.indexOf(query) === 0 : value.indexOf(query) !== -1
        }).slice(0, this.limit)
      }
      this.showDropdown = this.items.length > 0
    },
    setValue (value) {
      this.asign = value
      this.val = value
      this.items = []
      this.loading = false
      this.showDropdown = false
    },
    reset () { this.setValue(null) },
    setActive (index) { this.current = index },
    isActive (index) { return this.current === index },
    hit (e) {
      e.preventDefault()
      this.setValue(this.onHit(this.items[this.current], this))
    },
    up () {
      if (this.current > 0) {
        this.current--
      } else {
        this.current = this.items.length - 1
      }
    },
    down () {
      if (this.current < this.items.length - 1) {
        this.current++
      } else {
        this.current = 0
      }
    }
  },
  created () {
    this.__update = delayer(function () {
      if (!this.val) {
        this.reset()
        return
      }
      this.asign = ''
      if (this.async) {
        getJSON(this.onSearch(this.async, this.val), this.headers).then(data => {
          this.setItems(data)
        })
      } else if (this.data) {
        this.setItems(this.data)
      }
    }, 'delay', DELAY)
    this.__update()
  }
}