Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

fix(searchbox): prevent concurrent query updates from state while input is focused #1133

Merged
merged 2 commits into from
Jul 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/components/SearchBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
:reset-title="resetTitle"
:class-names="classNames"
v-model="currentRefinement"
ref="searchInput"
>
<template
v-slot:loading-indicator
Expand Down Expand Up @@ -148,6 +149,14 @@ export default {
this.$emit('update:modelValue', this.model);
this.state.refine(this.model);
}

// we return the local value if the input is focused to avoid
// concurrent updates when typing
const { searchInput } = this.$refs;
if (searchInput && searchInput.isFocused()) {
return this.localValue;
Haroenv marked this conversation as resolved.
Show resolved Hide resolved
}

return this.model || this.state.query || '';
},
set(val) {
Expand Down
3 changes: 3 additions & 0 deletions src/components/SearchInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ export default {
};
},
methods: {
isFocused() {
return document.activeElement === this.$refs.input;
},
onFormSubmit() {
const input = this.$refs.input;
input.blur();
Expand Down
15 changes: 15 additions & 0 deletions src/components/__tests__/SearchBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,21 @@ test('refine on empty string on form reset', async () => {
expect(state.refine).toHaveBeenCalledWith('');
});

test('keep local query when out of sync and input is focused', async () => {
const state = { ...defaultState, refine: jest.fn() };
__setState(state);

const wrapper = mount(SearchBox, { attachTo: document.body });
const input = wrapper.find('.ais-SearchBox-input');
input.element.focus();
await input.setValue('hello');

await wrapper.setData({ state: { query: 'hel' } });

expect(input.element.value).toBe('hello');
expect(state.refine).toHaveBeenLastCalledWith('hello');
});

test('overriding slots', () => {
__setState({
...defaultState,
Expand Down