Dropdown and Templating Support for AutoComplete

pull/12/head
cagataycivici 2019-01-28 15:20:01 +03:00
parent 6aa9680df9
commit 8cdb74834a
2 changed files with 82 additions and 17 deletions

View File

@ -2,6 +2,7 @@
<span :class="containerClass">
<input ref="input" :class="inputClass" v-bind="$attrs" v-on="listeners" :value="inputValue" type="text" autoComplete="off">
<i className="p-autocomplete-loader pi pi-spinner pi-spin" v-show="searching"></i>
<Button ref="dropdownButton" type="button" icon="pi pi-fw pi-chevron-down" class="p-autocomplete-dropdown" :disabled="disabled" @click="onDropdownClick" v-if="dropdown"/>
<transition name="p-input-overlay" @enter="onOverlayEnter" @leave="onOverlayLeave">
<div ref="overlay" class="p-autocomplete-panel" :style="{'max-height': scrollHeight}" v-if="overlayVisible">
<ul class="p-autocomplete-items p-autocomplete-list p-component">
@ -19,6 +20,7 @@
<script>
import ObjectUtils from '../utils/ObjectUtils';
import DomHandler from '../utils/DomHandler';
import Button from '../button/Button';
export default {
inheritAttrs: false,
@ -26,6 +28,10 @@ export default {
value: null,
suggestions: Array,
dropdown: Boolean,
dropdownMode: {
type: String,
default: 'blank'
},
multiple: Boolean,
disabled: Boolean,
field: String,
@ -67,6 +73,7 @@ export default {
},
methods: {
onOverlayEnter() {
this.$refs.overlay.style.zIndex = String(DomHandler.generateZIndex());
this.alignOverlay();
this.bindOutsideClickListener();
},
@ -79,20 +86,18 @@ export default {
bindOutsideClickListener() {
if (!this.outsideClickListener) {
this.outsideClickListener = (event) => {
if (this.overlayVisible && this.$refs.overlay && this.isOutsideClicked()) {
if (this.overlayVisible && this.$refs.overlay && this.isOutsideClicked(event)) {
this.hideOverlay();
}
};
document.addEventListener('click', this.outsideClickListener);
}
},
isOutsideClicked() {
if (this.multiple) {
return !this.$refs.overlay.contains(event.target) && event.target !== this.$refs.input;
}
else {
return !this.$refs.overlay.contains(event.target) && event.target !== this.$refs.input;
}
isOutsideClicked(event) {
return !this.$refs.overlay.contains(event.target) && event.target !== this.getInputElement() && !this.isDropdownClicked(event);
},
isDropdownClicked(event) {
return this.$refs.dropdownButton ? (event.target === this.$refs.dropdownButton || this.$refs.dropdownButton.$el.contains(event.target)) : false;
},
unbindOutsideClickListener() {
if (this.outsideClickListener) {
@ -120,6 +125,20 @@ export default {
this.focus();
this.hideOverlay();
},
onDropdownClick(event) {
this.focus();
const query = this.getInputElement().value;
if (this.dropdownMode === 'blank')
this.search(event, '', 'dropdown');
else if (this.dropdownMode === 'current')
this.search(event, query, 'dropdown');
this.$emit('click-dropdown', {
originalEvent: event,
query: query
});
},
getItemContent(item) {
return this.field ? ObjectUtils.resolveFieldData(item, this.field) : item;
},
@ -130,10 +149,7 @@ export default {
this.overlayVisible = false;
},
focus() {
if (this.multiple)
this.$refs.multiInput.focus();
else
this.$refs.input.focus();
this.getInputElement().focus();
},
search(event, query, source) {
//allow empty string but not undefined or null
@ -151,6 +167,9 @@ export default {
originalEvent: event,
query: query
});
},
getInputElement() {
return this.multiple ? this.$refs.inputMultiple : this.$refs.input;
}
},
computed: {
@ -213,12 +232,15 @@ export default {
return resolvedFieldData != null ? resolvedFieldData : this.value;
}
else
return value;
return this.value;
}
else {
return '';
}
}
},
components: {
'Button': Button
}
}
</script>

View File

@ -9,8 +9,19 @@
<div class="content-section implementation">
<h3 class="first">Basic</h3>
<AutoComplete v-model="country" :suggestions="countriesBasic" @complete="searchCountryBasic($event)" field="name" />
<AutoComplete v-model="country" :suggestions="filteredCountriesBasic" @complete="searchCountryBasic($event)" field="name" />
<span style="marginLeft: .5em">Country: {{country || 'none'}}</span>
<h3>Dropdown and Templating</h3>
<AutoComplete v-model="brand" :suggestions="filteredBrands" @complete="searchBrand($event)" placeholder="Hint: type 'v' or 'f'" :dropdown="true">
<template slot="item" slot-scope="{item}">
<div class="p-clearfix p-autocomplete-brand-item">
<img :alt="item" :src="'/demo/images/car/' + item + '.png'" />
<div>{{item}}</div>
</div>
</template>
</AutoComplete>
<span style="marginLeft: .5em">Brand: {{brand || 'none'}}</span>
</div>
</div>
</template>
@ -23,7 +34,10 @@ export default {
return {
countries: null,
country: null,
countriesBasic: null
filteredCountriesBasic: null,
brands: null,
brand: null,
filteredBrands: null
}
},
countryService: null,
@ -32,6 +46,7 @@ export default {
},
mounted() {
this.countryService.getCountries().then(data => this.countries = data);
this.brands = ['Audi', 'BMW', 'Fiat', 'Ford', 'Honda', 'Jaguar', 'Mercedes', 'Renault', 'Volvo'];
},
methods: {
searchCountryBasic(event) {
@ -39,13 +54,41 @@ export default {
let results = this.countries.filter((country) => {
return country.name.toLowerCase().startsWith(event.query.toLowerCase());
});
this.countriesBasic = results;
this.filteredCountriesBasic = results;
}, 250);
},
searchBrand(event) {
setTimeout(() => {
let results;
if (event.query.length === 0) {
results = [...this.brands];
}
else {
results = this.brands.filter((brand) => {
return brand.toLowerCase().startsWith(event.query.toLowerCase());
});
}
this.filteredBrands = results;
}, 250);
}
}
}
</script>
<style>
<style lang="scss">
.p-autocomplete-brand-item {
img {
width: 32px;
display: inline-block;
margin: 5px 0 2px 5px;
}
div {
font-size: 16px;
float: right;
margin: 10px 10px 0 0;
}
}
</style>