Skip to content

Commit

Permalink
Merge pull request #131 from AddSearch/sc-11132/refactor-autocomplete…
Browse files Browse the repository at this point in the history
…-and-keyword-states

feat: [sc-11132] Fix search ui states for autocomplete & keyword
  • Loading branch information
haoAddsearch authored Nov 13, 2024
2 parents c6fb4d4 + 3424e54 commit 06f8ce3
Show file tree
Hide file tree
Showing 13 changed files with 117 additions and 65 deletions.
2 changes: 1 addition & 1 deletion dist/addsearch-search-ui.min.css

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/addsearch-search-ui.min.js

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "addsearch-search-ui",
"version": "0.8.15",
"version": "0.9.0",
"description": "JavaScript library to develop Search UIs for the web",
"repository": {
"type": "git",
Expand Down
47 changes: 39 additions & 8 deletions src/actions/autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,20 @@ export function autocompleteSuggestions(client, keyword) {
type: AUTOCOMPLETE_SUGGESTIONS_CLEAR
};
}
return (dispatch) => {
return (dispatch, getState) => {
const keywordMinLengthToFetch = getState().keyword.minLengthRequiredToFetch;
if (keyword.length < keywordMinLengthToFetch) {
return;
}

dispatch(autocompleteFetchStart(SUGGESTIONS_JSON_KEY));
client.suggestions(keyword, (res) => dispatch(autocompleteSuggestionsResults(keyword, res)));
client.suggestions(keyword, (res) => {
const currentKeyword = getState().keyword.value;
if (currentKeyword === '') {
return;
}
dispatch(autocompleteSuggestionsResults(keyword, res));
});
};
}

Expand All @@ -36,9 +47,20 @@ export function autocompleteCustomFields(client, keyword, field) {
type: AUTOCOMPLETE_CUSTOM_FIELDS_CLEAR
};
}
return (dispatch) => {
return (dispatch, getState) => {
const keywordMinLengthToFetch = getState().keyword.minLengthRequiredToFetch;
if (keyword.length < keywordMinLengthToFetch) {
return;
}

dispatch(autocompleteFetchStart(CUSTOM_FIELDS_JSON_KEY));
client.autocomplete(field, keyword, (res) => dispatch(autocompleteCustomFieldsResults(res)));
client.autocomplete(field, keyword, (res) => {
const currentKeyword = getState().keyword.value;
if (currentKeyword === '') {
return;
}
dispatch(autocompleteCustomFieldsResults(res));
});
};
}

Expand All @@ -63,11 +85,20 @@ export function fetchAutocompleteSearchResultsStory(client, jsonKey, keyword, ap
type: AUTOCOMPLETE_SEARCH_CLEAR
};
}
return (dispatch) => {
return (dispatch, getState) => {
const keywordMinLengthToFetch = getState().keyword.minLengthRequiredToFetch;
if (keyword.length < keywordMinLengthToFetch) {
return;
}

dispatch(autocompleteFetchStart(jsonKey));
client.search(keyword, (res) =>
dispatch(autocompleteSearchResults(keyword, res, jsonKey, appendResults))
);
client.search(keyword, (res) => {
const currentKeyword = getState().keyword.value;
if (currentKeyword === '') {
return;
}
dispatch(autocompleteSearchResults(keyword, res, jsonKey, appendResults));
});
};
}

Expand Down
8 changes: 8 additions & 0 deletions src/actions/keyword.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const KEYWORD = 'KEYWORD';
export const KEYWORD_MIN_LENGTH_REQUIRED_TO_FETCH = 'KEYWORD_MIN_LENGTH_REQUIRED_TO_FETCH';

export function setKeyword(value, skipAutocomplete, searchFieldContainerId, setSearchFieldValue) {
return {
Expand All @@ -9,3 +10,10 @@ export function setKeyword(value, skipAutocomplete, searchFieldContainerId, setS
setSearchFieldValue: setSearchFieldValue || false
};
}

export function setKeywordMinLengthRequiredToFetch(opt) {
return {
type: KEYWORD_MIN_LENGTH_REQUIRED_TO_FETCH,
minLengthRequiredToFetch: opt.minLengthRequiredToFetch
};
}
12 changes: 5 additions & 7 deletions src/actions/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@ export const SEARCH_FETCH_START = 'SEARCH_FETCH_START';
export const SEARCH_RESULTS = 'SEARCH_RESULTS';
export const CLEAR_SEARCH_RESULTS = 'CLEAR_SEARCH_RESULTS';

export function start() {
return {
type: START
};
}

function _matchKeywordToCustomFieldValue(keyword, hits, field) {
return hits.find((hit) => {
if (!hit.custom_fields || !hit.custom_fields[field]) {
Expand Down Expand Up @@ -53,7 +47,11 @@ export function fetchSearchResultsStory(
type: CLEAR_SEARCH_RESULTS
};
}
return (dispatch) => {
return (dispatch, getState) => {
const keywordMinLengthToFetch = getState().keyword.minLengthRequiredToFetch;
if (isHistoryDebounced && keyword.length < keywordMinLengthToFetch) {
return;
}
dispatch({
type: SEARCH_FETCH_START
});
Expand Down
40 changes: 20 additions & 20 deletions src/components/autocomplete/autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default class Autocomplete {
this.hasConversationalSearch = hasConversationalSearch;
this.conf = conf;
this.lastOnmouseOver = null;
this.minLengthRequired = this.reduxStore.getState().keyword.minLengthRequiredToFetch;

if (this.conf.hideAutomatically === false) {
this.reduxStore.dispatch(setHideAutomatically(false));
Expand Down Expand Up @@ -60,8 +61,15 @@ export default class Autocomplete {
}

autocompleteResultsChanged(state) {
// Wait until pending API requests have finished (if multiple autocomplete clients)
if (state.pendingRequests.length !== 0) {
if (state.dropRendering) {
this.clearRenderedHtml();
return;
}
const currentKeyword = this.reduxStore.getState().keyword.value;
const shouldSkipRendering =
state.pendingRequests.length > 0 || currentKeyword.length < this.minLengthRequired;

if (shouldSkipRendering) {
return;
}

Expand Down Expand Up @@ -92,11 +100,10 @@ export default class Autocomplete {

keywordChanged(kw) {
// Fetch suggestions if keyword was typed, not externally set (e.g. by browser's back button)
const keyword = kw.skipAutocomplete === false ? kw.value : null;

if (keyword === '') {
this.reduxStore.dispatch(autocompleteHideAndDropRendering());
if (kw.skipAutocomplete) {
return;
}
const keyword = kw.value;

this.conf.sources.forEach((source) => {
const client = source.client || this.client;
Expand Down Expand Up @@ -137,23 +144,15 @@ export default class Autocomplete {
});
}

clearRenderedHtml = () => {
document.getElementById(this.conf.containerId).innerHTML = '';
this.renderedHtml = '';
};

render(autocompleteState) {
// Hide autocomplete after a search is triggered
if (autocompleteState.dropRendering && this.renderedHtml) {
document.getElementById(this.conf.containerId).innerHTML = '';
this.renderedHtml = '';
return;
}

// Don't re-render while API requests are pending
if (autocompleteState.pendingRequests.length !== 0 || autocompleteState.dropRendering) {
return;
}

// Hide autocomplete
if (autocompleteState.visible === false) {
document.getElementById(this.conf.containerId).innerHTML = '';
this.renderedHtml = '';
this.clearRenderedHtml();
return;
}

Expand Down Expand Up @@ -238,6 +237,7 @@ export default class Autocomplete {
suggestionMouseDown(e) {
const keyword = e.target.getAttribute('data-keyword');
const store = this.reduxStore;
store.dispatch(autocompleteHideAndDropRendering());
store.dispatch(setKeyword(keyword, true, null, true));

// Redirect to search results page
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

.header {
display: flex;
align-items: start;
align-items: flex-start;
justify-content: space-between;
}

Expand Down Expand Up @@ -144,7 +144,7 @@
margin-top: 12px;
display: flex;
align-items: center;
justify-content: end;
justify-content: flex-end;
gap: 24px;

.copy-confirm-message {
Expand Down
20 changes: 11 additions & 9 deletions src/components/searchfield/searchfield.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import handlebars from 'handlebars';
import PRECOMPILED_SEARCHFIELD_TEMPLATE from './precompile-templates/searchfield.handlebars';

import {
autocompleteHide,
autocompleteShow,
keyboardEvent,
setActiveSuggestion,
Expand All @@ -13,7 +12,7 @@ import {
autocompleteHideAndDropRendering
} from '../../actions/autocomplete';
import { setPage } from '../../actions/pagination';
import { setKeyword } from '../../actions/keyword';
import { setKeyword, setKeywordMinLengthRequiredToFetch } from '../../actions/keyword';
import { observeStoreByKey } from '../../store';
import { MATCH_ALL_QUERY, WARMUP_QUERY_PREFIX } from '../../index';
import { redirectToSearchResultsPage } from '../../util/history';
Expand All @@ -36,9 +35,15 @@ export default class SearchField {
this.matchAllQuery = matchAllQueryWhenSearchFieldEmpty;
this.minLengthToShowResults = conf.minLengthToShowResults || 1;
this.firstRenderDone = false;
this.firstSelectorBindDone = false;
this.onSearch = onSearch;

const minLengthToShowResults = conf.minLengthToShowResults || 0;
this.reduxStore.dispatch(
setKeywordMinLengthRequiredToFetch({
minLengthRequiredToFetch: minLengthToShowResults
})
);

if (conf.selectorToBind) {
this.bindContainer();
observeStoreByKey(this.reduxStore, 'keyword', (kw) => {
Expand Down Expand Up @@ -167,8 +172,8 @@ export default class SearchField {
if (keyword === '' && this.matchAllQuery) {
keyword = MATCH_ALL_QUERY;
}
store.dispatch(autocompleteHideAndDropRendering());
store.dispatch(setKeyword(keyword, true, null, false));
store.dispatch(autocompleteHide());
this.redirectOrSearch(keyword);
}

Expand Down Expand Up @@ -270,11 +275,8 @@ export default class SearchField {
}

const skipAutocomplete = this.conf.ignoreAutocomplete === true;
if (keyword.length < this.minLengthToShowResults) {
return;
}
store.dispatch(setKeyword(keyword, skipAutocomplete, this.conf.containerId));

store.dispatch(autocompleteShow());
if (this.conf.searchAsYouType === true) {
this.executeSearch(this.client, keyword, true);
}
Expand Down Expand Up @@ -316,7 +318,7 @@ export default class SearchField {

onblur() {
if (this.reduxStore.getState().autocomplete.hideAutomatically) {
this.reduxStore.dispatch(autocompleteHide());
this.reduxStore.dispatch(autocompleteHideAndDropRendering());
}
}
}
12 changes: 7 additions & 5 deletions src/reducers/autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,21 @@ export default function searchsuggestions(state = initialState, action) {
}

return Object.assign({}, state, {
pendingRequests: addPendingReq,
dropRendering: false
pendingRequests: addPendingReq
});

case AUTOCOMPLETE_SUGGESTIONS_CLEAR:
return Object.assign({}, state, {
suggestions: [],
activeSuggestionIndex: null
activeSuggestionIndex: null,
pendingRequests: []
});

case AUTOCOMPLETE_CUSTOM_FIELDS_CLEAR:
return Object.assign({}, state, {
customFields: [],
activeSuggestionIndex: null
activeSuggestionIndex: null,
pendingRequests: []
});

case AUTOCOMPLETE_SUGGESTIONS_RESULTS:
Expand Down Expand Up @@ -152,7 +153,8 @@ export default function searchsuggestions(state = initialState, action) {

case AUTOCOMPLETE_SHOW:
return Object.assign({}, state, {
visible: true
visible: true,
dropRendering: false
});

case HIDE_AUTOMATICALLY:
Expand Down
10 changes: 8 additions & 2 deletions src/reducers/keyword.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { KEYWORD } from '../actions/keyword';
import { KEYWORD, KEYWORD_MIN_LENGTH_REQUIRED_TO_FETCH } from '../actions/keyword';

const initialState = {
value: '',
skipAutocomplete: false,
searchFieldContainerId: null,
setSearchFieldValue: null
setSearchFieldValue: null,
minLengthRequiredToFetch: 0
};

export default function keyword(state = initialState, action) {
Expand All @@ -17,6 +18,11 @@ export default function keyword(state = initialState, action) {
setSearchFieldValue: action.setSearchFieldValue
});

case KEYWORD_MIN_LENGTH_REQUIRED_TO_FETCH:
return Object.assign({}, state, {
minLengthRequiredToFetch: action.minLengthRequiredToFetch
});

default:
return state;
}
Expand Down
11 changes: 8 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1500,9 +1500,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0"

caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001578, caniuse-lite@^1.0.30001580:
version "1.0.30001581"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz"
integrity sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ==
version "1.0.30001680"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz"
integrity sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==

chalk@^2.4.2:
version "2.4.2"
Expand Down Expand Up @@ -3075,6 +3075,11 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
picocolors "^1.0.0"
source-map-js "^1.0.2"

prettier@^3.3.3:
version "3.3.3"
resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz"
integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==

punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz"
Expand Down

0 comments on commit 06f8ce3

Please sign in to comment.