Fixed #1597 - keyboard navigation is broken in AutoComplete with VirtualScroller

pull/1792/head
mertsincan 2021-11-18 10:54:19 +03:00
parent a02160367c
commit 23c6bc4668
1 changed files with 16 additions and 10 deletions

View File

@ -22,9 +22,9 @@
<slot name="header" :value="modelValue" :suggestions="suggestions"></slot> <slot name="header" :value="modelValue" :suggestions="suggestions"></slot>
<VirtualScroller :ref="virtualScrollerRef" v-bind="virtualScrollerOptions" :style="{'height': scrollHeight}" :items="suggestions" :disabled="virtualScrollerDisabled"> <VirtualScroller :ref="virtualScrollerRef" v-bind="virtualScrollerOptions" :style="{'height': scrollHeight}" :items="suggestions" :disabled="virtualScrollerDisabled">
<template v-slot:content="{ styleClass, contentRef, items, getItemOptions }"> <template v-slot:content="{ styleClass, contentRef, items, getItemOptions }">
<ul :id="listId" :ref="contentRef" :class="['p-autocomplete-items', styleClass]" role="listbox"> <ul :id="listId" :ref="(el) => listRef(el, contentRef)" :class="['p-autocomplete-items', styleClass]" role="listbox">
<template v-if="!optionGroupLabel"> <template v-if="!optionGroupLabel">
<li v-for="(item, i) of items" class="p-autocomplete-item" :key="i" @click="selectItem($event, item)" role="option" v-ripple> <li v-for="(item, i) of items" class="p-autocomplete-item" :key="getOptionRenderKey(item)" @click="selectItem($event, item)" role="option" v-ripple :data-index="getOptionIndex(i, getItemOptions)">
<slot name="item" :item="item" :index="getOptionIndex(i, getItemOptions)">{{getItemContent(item)}}</slot> <slot name="item" :item="item" :index="getOptionIndex(i, getItemOptions)">{{getItemContent(item)}}</slot>
</li> </li>
</template> </template>
@ -33,7 +33,7 @@
<li class="p-autocomplete-item-group"> <li class="p-autocomplete-item-group">
<slot name="optiongroup" :item="optionGroup" :index="getOptionIndex(i, getItemOptions)">{{getOptionGroupLabel(optionGroup)}}</slot> <slot name="optiongroup" :item="optionGroup" :index="getOptionIndex(i, getItemOptions)">{{getOptionGroupLabel(optionGroup)}}</slot>
</li> </li>
<li v-for="(item, j) of getOptionGroupChildren(optionGroup)" class="p-autocomplete-item" :key="j" @click="selectItem($event, item)" role="option" v-ripple :data-group="i" :data-index="j"> <li v-for="(item, j) of getOptionGroupChildren(optionGroup)" class="p-autocomplete-item" :key="j" @click="selectItem($event, item)" role="option" v-ripple :data-group="i" :data-index="getOptionIndex(j, getItemOptions)">
<slot name="item" :item="item" :index="getOptionIndex(j, getItemOptions)">{{getItemContent(item)}}</slot> <slot name="item" :item="item" :index="getOptionIndex(j, getItemOptions)">{{getItemContent(item)}}</slot>
</li> </li>
</template> </template>
@ -174,6 +174,9 @@ export default {
getOptionIndex(index, fn) { getOptionIndex(index, fn) {
return this.virtualScrollerDisabled ? index : (fn && fn(index)['index']); return this.virtualScrollerDisabled ? index : (fn && fn(index)['index']);
}, },
getOptionRenderKey(option) {
return this.getItemContent(option);
},
getOptionGroupRenderKey(optionGroup) { getOptionGroupRenderKey(optionGroup) {
return ObjectUtils.resolveFieldData(optionGroup, this.optionGroupLabel); return ObjectUtils.resolveFieldData(optionGroup, this.optionGroupLabel);
}, },
@ -191,8 +194,7 @@ export default {
this.bindResizeListener(); this.bindResizeListener();
if (this.autoHighlight && this.suggestions && this.suggestions.length) { if (this.autoHighlight && this.suggestions && this.suggestions.length) {
let itemList = DomHandler.findSingle(this.overlay, '.p-autocomplete-items'); DomHandler.addClass(this.list.firstElementChild, 'p-highlight');
DomHandler.addClass(itemList.firstElementChild, 'p-highlight');
} }
}, },
onOverlayLeave() { onOverlayLeave() {
@ -394,7 +396,7 @@ export default {
}, },
onKeyDown(event) { onKeyDown(event) {
if (this.overlayVisible) { if (this.overlayVisible) {
let highlightItem = DomHandler.findSingle(this.overlay, 'li.p-highlight'); let highlightItem = DomHandler.findSingle(this.list, 'li.p-highlight');
switch(event.which) { switch(event.which) {
//down //down
@ -404,11 +406,11 @@ export default {
if (nextElement) { if (nextElement) {
DomHandler.addClass(nextElement, 'p-highlight'); DomHandler.addClass(nextElement, 'p-highlight');
DomHandler.removeClass(highlightItem, 'p-highlight'); DomHandler.removeClass(highlightItem, 'p-highlight');
DomHandler.scrollInView(this.overlay, nextElement); nextElement.scrollIntoView({ block: 'nearest', inline: 'start' });
} }
} }
else { else {
highlightItem = this.overlay.firstElementChild.firstElementChild; highlightItem = this.list.firstElementChild;
if (DomHandler.hasClass(highlightItem, 'p-autocomplete-item-group')) { if (DomHandler.hasClass(highlightItem, 'p-autocomplete-item-group')) {
highlightItem = this.findNextItem(highlightItem); highlightItem = this.findNextItem(highlightItem);
} }
@ -428,7 +430,7 @@ export default {
if (previousElement) { if (previousElement) {
DomHandler.addClass(previousElement, 'p-highlight'); DomHandler.addClass(previousElement, 'p-highlight');
DomHandler.removeClass(highlightItem, 'p-highlight'); DomHandler.removeClass(highlightItem, 'p-highlight');
DomHandler.scrollInView(this.overlay, previousElement); previousElement.scrollIntoView({ block: 'nearest', inline: 'start' });
} }
} }
@ -492,7 +494,7 @@ export default {
this.selectItem(event, this.getOptionGroupChildren(optionGroup)[item.dataset.index]); this.selectItem(event, this.getOptionGroupChildren(optionGroup)[item.dataset.index]);
} }
else { else {
this.selectItem(event, this.suggestions[DomHandler.index(item)]); this.selectItem(event, this.suggestions[item.dataset.index]);
} }
}, },
findNextItem(item) { findNextItem(item) {
@ -553,6 +555,10 @@ export default {
overlayRef(el) { overlayRef(el) {
this.overlay = el; this.overlay = el;
}, },
listRef(el, contentRef) {
this.list = el;
contentRef && contentRef(el); // for virtualScroller
},
virtualScrollerRef(el) { virtualScrollerRef(el) {
this.virtualScroller = el; this.virtualScroller = el;
}, },