Fixed #872 - forceSelection for AutoComplete

pull/938/head
Cagatay Civici 2021-02-03 14:24:42 +03:00
parent 10e8f8600c
commit e0cf7956c0
4 changed files with 53 additions and 9 deletions

View File

@ -13,6 +13,7 @@ declare class AutoComplete extends Vue {
appendTo?: string;
inputStyle?: any;
inputClass?: string;
forceSelection?: boolean;
$emit(eventName: 'item-select', e: {originalEvent: Event, value: any}): this;
$emit(eventName: 'item-unselect', e: {originalEvent: Event, value: any}): this;
$emit(eventName: 'dropdown-click', e: {originalEvent: Event, query: string}): this;

View File

@ -1,14 +1,14 @@
<template>
<span ref="container" :class="containerClass" aria-haspopup="listbox" :aria-owns="listId" :aria-expanded="overlayVisible" :style="style">
<input ref="input" :class="inputFieldClass" :style="inputStyle" v-bind="$attrs" :value="inputValue" @input="onInput" @focus="onFocus" @blur="onBlur" @keydown="onKeyDown" type="text" autoComplete="off" v-if="!multiple"
role="searchbox" aria-autocomplete="list" :aria-controls="listId">
<input ref="input" :class="inputFieldClass" :style="inputStyle" v-bind="$attrs" :value="inputValue" @input="onInput" @focus="onFocus" @blur="onBlur" @keydown="onKeyDown" @change="onChange"
type="text" autoComplete="off" v-if="!multiple" role="searchbox" aria-autocomplete="list" :aria-controls="listId">
<ul ref="multiContainer" :class="multiContainerClass" v-if="multiple" @click="onMultiContainerClick">
<li v-for="(item, i) of modelValue" :key="i" class="p-autocomplete-token">
<span class="p-autocomplete-token-label">{{getItemContent(item)}}</span>
<span class="p-autocomplete-token-icon pi pi-times-circle" @click="removeItem($event, i)"></span>
</li>
<li class="p-autocomplete-input-token">
<input ref="input" type="text" autoComplete="off" v-bind="$attrs" @input="onInput" @focus="onFocus" @blur="onBlur" @keydown="onKeyDown"
<input ref="input" type="text" autoComplete="off" v-bind="$attrs" @input="onInput" @focus="onFocus" @blur="onBlur" @keydown="onKeyDown" @change="onChange"
role="searchbox" aria-autocomplete="list" :aria-controls="listId">
</li>
</ul>
@ -77,6 +77,10 @@ export default {
type: String,
default: null
},
forceSelection: {
type: Boolean,
default: false
},
inputClass: null,
inputStyle: null,
class: null,
@ -403,6 +407,30 @@ export default {
}
}
},
onChange(event) {
if (this.forceSelection) {
let valid = false;
let inputValue = event.target.value.trim();
if (this.suggestions) {
for (let item of this.suggestions) {
let itemValue = this.field ? ObjectUtils.resolveFieldData(item, this.field) : item;
if (itemValue && inputValue === itemValue.trim()) {
valid = true;
this.selectItem(event, item);
break;
}
}
}
if (!valid) {
this.$refs.input.value = '';
this.inputTextValue = '';
this.$emit('clear');
this.$emit('update:modelValue', null);
}
}
},
isSelected(val) {
let selected = false;
if (this.modelValue && this.modelValue.length) {

View File

@ -13,8 +13,8 @@
<h5>Basic</h5>
<AutoComplete v-model="selectedCountry1" :suggestions="filteredCountries" @complete="searchCountry($event)" field="name" />
<h5>Dropdown and Templating</h5>
<AutoComplete v-model="selectedCountry2" :suggestions="filteredCountries" @complete="searchCountry($event)" :dropdown="true" field="name">
<h5>Dropdown, Templating and Force Selection</h5>
<AutoComplete v-model="selectedCountry2" :suggestions="filteredCountries" @complete="searchCountry($event)" :dropdown="true" field="name" forceSelection>
<template #item="slotProps">
<div class="country-item">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.item.code.toLowerCase()" />

View File

@ -60,6 +60,14 @@ export default {
<pre v-code><code>
&lt;AutoComplete field="label" v-model="selectedCountry" :suggestions="filteredCountriesBasic" @complete="searchCountryBasic($event)" /&gt;
</code></pre>
<h5>Force Selection</h5>
<p>ForceSelection mode validates the manual input to check whether it also exists in the suggestions list, if not the input value is cleared
to make sure the value passed to the model is always one of the suggestions. Simply enable <i>forceSelection</i> to enforce that input is always from the suggestion list.</p>
<pre v-code><code>
&lt;AutoComplete forceSelection v-model="brand" :suggestions="filteredBrands" @complete="searchBrand($event)" /&gt;
</code></pre>
<h5>Templating</h5>
@ -158,6 +166,13 @@ export default {
<td>string</td>
<td>null</td>
<td>Style class of the input field.</td>
</tr>
<tr>
<td>forceSelection</td>
<td>boolean</td>
<td>false</td>
<td>When present, autocomplete clears the manual input if it does not match of the suggestions to force only
accepting values from the suggestions.</td>
</tr>
</tbody>
</table>
@ -270,8 +285,8 @@ export default {
&lt;h5&gt;Basic&lt;/h5&gt;
&lt;AutoComplete v-model="selectedCountry1" :suggestions="filteredCountries" @complete="searchCountry($event)" field="name" /&gt;
&lt;h5&gt;Dropdown and Templating&lt;/h5&gt;
&lt;AutoComplete v-model="selectedCountry2" :suggestions="filteredCountries" @complete="searchCountry($event)" :dropdown="true" field="name"&gt;
&lt;h5&gt;Dropdown, Templating and Force Selection&lt;/h5&gt;
&lt;AutoComplete v-model="selectedCountry2" :suggestions="filteredCountries" @complete="searchCountry($event)" :dropdown="true" field="name" forceSelection&gt;
&lt;template #item="slotProps"&gt;
&lt;div class="country-item"&gt;
&lt;img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.item.code.toLowerCase()" /&gt;
@ -343,8 +358,8 @@ export default {
<h5>Basic</h5>
<AutoComplete v-model="selectedCountry1" :suggestions="filteredCountries" @complete="searchCountry($event)" field="name" />
<h5>Dropdown and Templating</h5>
<AutoComplete v-model="selectedCountry2" :suggestions="filteredCountries" @complete="searchCountry($event)" :dropdown="true" field="name">
<h5>Dropdown, Templating and Force Selection</h5>
<AutoComplete v-model="selectedCountry2" :suggestions="filteredCountries" @complete="searchCountry($event)" :dropdown="true" field="name" forceSelection>
<template #item="slotProps">
<div class="country-item">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" />