autocomplete field
This commit is contained in:
		@ -1,11 +1,26 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="control">
 | 
			
		||||
        <datalist :id="listId">
 | 
			
		||||
            <option v-for="item in items" :key="item.path"
 | 
			
		||||
                :value="item[field]"></option>
 | 
			
		||||
        </datalist>
 | 
			
		||||
        <input type="text" :name="name" :placeholder="placeholder"
 | 
			
		||||
            :list="listId" @keyup="onKeyUp"/>
 | 
			
		||||
    <div :class="dropdownClass">
 | 
			
		||||
        <div class="dropdown-trigger is-fullwidth">
 | 
			
		||||
            <div class="control is-expanded">
 | 
			
		||||
                <input type="hidden" :name="name"
 | 
			
		||||
                    :value="selectedValue" />
 | 
			
		||||
                <input type="text" :placeholder="placeholder"
 | 
			
		||||
                    ref="input" class="input is-fullwidth"
 | 
			
		||||
                    @keyup="onKeyUp" @focus="active=true" @click="active=true"/>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="dropdown-menu is-fullwidth">
 | 
			
		||||
            <div class="dropdown-content" style="overflow: hidden">
 | 
			
		||||
                <a v-for="(item, index) in items" :key="item.id"
 | 
			
		||||
                    :class="['dropdown-item', index === this.selectedIndex ? 'is-active':'']"
 | 
			
		||||
                    @click="select(index); active=false" :title="item.data[labelField]">
 | 
			
		||||
                    <slot name="item" :index="index" :item="item" :value-field="valueField"
 | 
			
		||||
                        :labelField="labelField">
 | 
			
		||||
                    {{ item.data[labelField] }}
 | 
			
		||||
                    </slot>
 | 
			
		||||
                </a>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@ -18,38 +33,79 @@ export default {
 | 
			
		||||
        model: Function,
 | 
			
		||||
        placeholder: String,
 | 
			
		||||
        name: String,
 | 
			
		||||
        field: String,
 | 
			
		||||
        valueField: {type: String, default: 'id'},
 | 
			
		||||
        labelField: String,
 | 
			
		||||
        valueField: {type: String, default: null},
 | 
			
		||||
        count: {type: Number, count: 10},
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            active: false,
 | 
			
		||||
            value: '',
 | 
			
		||||
            items: [],
 | 
			
		||||
            selected: null,
 | 
			
		||||
            selectedIndex: -1,
 | 
			
		||||
            isFetching: false,
 | 
			
		||||
            listId: `autocomplete-${ Math.random() }`.replace('.',''),
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
        select(option, value=null) {
 | 
			
		||||
            if(!option && value !== null)
 | 
			
		||||
                option = this.items.find(item => item[this.field] == value)
 | 
			
		||||
    computed: {
 | 
			
		||||
        selected() {
 | 
			
		||||
            let index = this.selectedIndex
 | 
			
		||||
            if(index<0)
 | 
			
		||||
                return null
 | 
			
		||||
            index = Math.min(index, this.items.length-1)
 | 
			
		||||
            return this.items[index]
 | 
			
		||||
        },
 | 
			
		||||
        
 | 
			
		||||
        selectedValue() {
 | 
			
		||||
            const sel = this.selected
 | 
			
		||||
            return sel && (this.valueField ?
 | 
			
		||||
                    sel.data[this.valueField] : sel.id)
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
            this.selected = option
 | 
			
		||||
            this.$emit('select', option)
 | 
			
		||||
        selectedLabel() {
 | 
			
		||||
            const sel = this.selected
 | 
			
		||||
            return sel && sel.data[this.labelField]
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        dropdownClass() {
 | 
			
		||||
            const active = this.active && this.items.length;
 | 
			
		||||
            return ['dropdown', active ? 'is-active':'']
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
        select(index, relative) {
 | 
			
		||||
            if(relative)
 | 
			
		||||
                index += this.selectedIndex
 | 
			
		||||
            else if(index == this.selectedIndex)
 | 
			
		||||
                return
 | 
			
		||||
        
 | 
			
		||||
            this.selectedIndex =  Math.max(-1, Math.min(index, this.items.length-1))
 | 
			
		||||
            if(index >= 0) {
 | 
			
		||||
                this.$refs.input.value = this.selectedLabel
 | 
			
		||||
                this.$refs.input.focus()
 | 
			
		||||
            }
 | 
			
		||||
            this.$emit('select', index, this.selected, this.selectedValue)
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        onKeyUp: function(event) {
 | 
			
		||||
            this.active = true
 | 
			
		||||
            switch(event.keyCode) {
 | 
			
		||||
                case 27: this.active = false
 | 
			
		||||
                         return
 | 
			
		||||
                case 38: this.select(-1, true)
 | 
			
		||||
                         return
 | 
			
		||||
                case 40: this.select(1, true)
 | 
			
		||||
                         return
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            const value = event.target.value
 | 
			
		||||
            if(value === this.value)
 | 
			
		||||
                return
 | 
			
		||||
 | 
			
		||||
            if(value !== undefined && value !== null)
 | 
			
		||||
                this.value = value
 | 
			
		||||
                
 | 
			
		||||
            this.value = value;
 | 
			
		||||
            if(!value)
 | 
			
		||||
                return this.select(null)
 | 
			
		||||
 | 
			
		||||
@ -64,7 +120,7 @@ export default {
 | 
			
		||||
            return this.model.fetch(this.url.replace('${query}', query), {many:true})
 | 
			
		||||
                .then(items => { this.items = items || []
 | 
			
		||||
                                 this.isFetching = false
 | 
			
		||||
                                 this.select(null, query)
 | 
			
		||||
                                 this.active = items.length > 0
 | 
			
		||||
                                 return items },
 | 
			
		||||
                      data => {this.isFetching = false; Promise.reject(data)})
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user