From 06f86b2a0e183136366a32b68a271146a1c42d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 6 Aug 2015 18:03:13 +0200 Subject: [PATCH 1/8] first cut: test queue inheritance --- js/actions/piece_list_actions.js | 6 +++++- js/utils/action_queue_utils.js | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 js/utils/action_queue_utils.js diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index 1ebe7f42..56e42952 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -3,10 +3,14 @@ import alt from '../alt'; import Q from 'q'; +import ActionQueue from '../utils/action_queue_utils'; + import PieceListFetcher from '../fetchers/piece_list_fetcher'; -class PieceListActions { +class PieceListActions extends ActionQueue { constructor() { + super(); + this.generateActions( 'updatePieceList', 'updatePieceListRequestActions', diff --git a/js/utils/action_queue_utils.js b/js/utils/action_queue_utils.js new file mode 100644 index 00000000..6009198a --- /dev/null +++ b/js/utils/action_queue_utils.js @@ -0,0 +1,18 @@ +'use strict'; + + +class ActionQueue { + constructor() { + let actionClass = this.constructor.prototype; + let actionClassPropertyNames = Object.getOwnPropertyNames(actionClass); + + this.constructor = actionClass.constructor; + + for(let i = 1; i < actionClassPropertyNames.length; i++) { + let methodName = actionClassPropertyNames[i]; + actionClass[methodName] = () => console.log('hello'); + } + } +} + +export default ActionQueue; \ No newline at end of file From 02eafaa80c2e2338b59c0f1db7400e229b48b01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 12 Oct 2015 13:57:37 +0200 Subject: [PATCH 2/8] Isolate SearchBar from PieceListToolbar and start implement threshold logic --- js/actions/piece_list_actions.js | 8 +-- .../piece_list_toolbar.js | 29 +++----- js/components/search_bar.js | 68 +++++++++++++++++++ js/utils/action_queue_utils.js | 18 ----- 4 files changed, 79 insertions(+), 44 deletions(-) create mode 100644 js/components/search_bar.js delete mode 100644 js/utils/action_queue_utils.js diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index 31f1bca5..87304ca7 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -3,14 +3,11 @@ import alt from '../alt'; import Q from 'q'; -import ActionQueue from '../utils/action_queue_utils'; - import PieceListFetcher from '../fetchers/piece_list_fetcher'; -class PieceListActions extends ActionQueue { - constructor() { - super(); +class PieceListActions { + constructor() { this.generateActions( 'updatePieceList', 'updatePieceListRequestActions', @@ -35,7 +32,6 @@ class PieceListActions extends ActionQueue { }); // afterwards, we can load the list - return Q.Promise((resolve, reject) => { PieceListFetcher .fetch(page, pageSize, search, orderBy, orderAsc, filterBy) diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js index 0890db00..d2c3265f 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -4,13 +4,10 @@ import React from 'react'; import PieceListToolbarFilterWidget from './piece_list_toolbar_filter_widget'; import PieceListToolbarOrderWidget from './piece_list_toolbar_order_widget'; +import SearchBar from '../search_bar'; -import Input from 'react-bootstrap/lib/Input'; -import Glyphicon from 'react-bootstrap/lib/Glyphicon'; -import { getLangText } from '../../utils/lang_utils'; let PieceListToolbar = React.createClass({ - propTypes: { className: React.PropTypes.string, searchFor: React.PropTypes.func, @@ -39,11 +36,6 @@ let PieceListToolbar = React.createClass({ ]) }, - searchFor() { - let searchTerm = this.refs.search.getInputDOMNode().value; - this.props.searchFor(searchTerm); - }, - getFilterWidget(){ if (this.props.filterParams){ return ( @@ -55,6 +47,7 @@ let PieceListToolbar = React.createClass({ } return null; }, + getOrderWidget(){ if (this.props.orderParams){ return ( @@ -68,24 +61,20 @@ let PieceListToolbar = React.createClass({ }, render() { - let searchIcon = ; + const { className, children, searchFor } = this.props; return ( -
+
- {this.props.children} - - - + {children} + {this.getOrderWidget()} {this.getFilterWidget()} diff --git a/js/components/search_bar.js b/js/components/search_bar.js new file mode 100644 index 00000000..942b63cd --- /dev/null +++ b/js/components/search_bar.js @@ -0,0 +1,68 @@ +'use strict'; + +import React from 'react/addons'; + +import Input from 'react-bootstrap/lib/Input'; +import Glyphicon from 'react-bootstrap/lib/Glyphicon'; +import { getLangText } from '../utils/lang_utils'; + + +const { func, string, number } = React.PropTypes; +const { update } = React.addons; + +const SearchBar = React.createClass({ + propTypes: { + searchFor: func.isRequired, + className: string, + + // in milliseconds + threshold: number.isRequired + }, + + getInitialState() { + return { + timers: [], + currentSearchQuery: '' + }; + }, + + startTimers(searchQuery) { + const { timers } = this.state; + const { threshold } = this.props; + const timer = { + searchQuery, + cb: setTimeout(this.evaluateTimer, threshold) + }; + + + const newTimers = update(timers, {$push: [timer]}); + this.setState({ timers: newTimers }); + }, + + evaluateTimer() { + console.log(this); + }, + + handleChange({ target: { value }}) { + this.startTimers(value); + this.setState({ currentSearchQuery: value }); + }, + + render() { + const searchIcon = ; + const { className } = this.props; + + return ( + + + + ); + } +}); + + +export default SearchBar; \ No newline at end of file diff --git a/js/utils/action_queue_utils.js b/js/utils/action_queue_utils.js deleted file mode 100644 index 6009198a..00000000 --- a/js/utils/action_queue_utils.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; - - -class ActionQueue { - constructor() { - let actionClass = this.constructor.prototype; - let actionClassPropertyNames = Object.getOwnPropertyNames(actionClass); - - this.constructor = actionClass.constructor; - - for(let i = 1; i < actionClassPropertyNames.length; i++) { - let methodName = actionClassPropertyNames[i]; - actionClass[methodName] = () => console.log('hello'); - } - } -} - -export default ActionQueue; \ No newline at end of file From c59f5267ce7455f7b0c89050610a8b1f54c509b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 12 Oct 2015 16:38:00 +0200 Subject: [PATCH 3/8] add threshold functionality to SearchBar --- js/actions/piece_list_actions.js | 2 +- .../piece_list_toolbar.js | 6 ++- js/components/piece_list.js | 1 + js/components/search_bar.js | 42 +++++++++++++++---- 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index 87304ca7..f4231a0b 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -22,10 +22,10 @@ class PieceListActions { this.actions.updatePieceList({ page, pageSize, - search, orderBy, orderAsc, filterBy, + search: '', pieceList: [], pieceListCount: -1, unfilteredPieceListCount: -1 diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js index d2c3265f..8f65fb31 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -11,6 +11,7 @@ let PieceListToolbar = React.createClass({ propTypes: { className: React.PropTypes.string, searchFor: React.PropTypes.func, + searchQuery: React.PropTypes.string, filterParams: React.PropTypes.arrayOf( React.PropTypes.shape({ label: React.PropTypes.string, @@ -61,7 +62,7 @@ let PieceListToolbar = React.createClass({ }, render() { - const { className, children, searchFor } = this.props; + const { className, children, searchFor, searchQuery } = this.props; return (
@@ -74,7 +75,8 @@ let PieceListToolbar = React.createClass({ + searchQuery={searchQuery} + threshold={500}/> {this.getOrderWidget()} {this.getFilterWidget()} diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 35dcaba0..908c2821 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -157,6 +157,7 @@ let PieceList = React.createClass({ { + const { timers } = this.state; + + if(timers.length <= timerIndex + 1) { + // clean the timers array + this.setState({ timers: [], searching: true }, () => { + // search for the query + this.props.searchFor(searchQuery); + }); + } + }; }, handleChange({ target: { value }}) { this.startTimers(value); - this.setState({ currentSearchQuery: value }); + this.setState({ searchQuery: value }); }, render() { - const searchIcon = ; + let searchIcon = ; const { className } = this.props; + const { searching } = this.state; + + if(searching) { + searchIcon = ; + } return ( From 6d36be531131299512bfe41286540c7fff06dfb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 12 Oct 2015 17:10:04 +0200 Subject: [PATCH 4/8] Add documentation for SearchBar and put threshold into AppConstants --- .../piece_list_toolbar.js | 4 +- js/components/search_bar.js | 58 ++++++++++++++++--- js/constants/application_constants.js | 3 +- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js index 8f65fb31..b7db7ce6 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -6,6 +6,8 @@ import PieceListToolbarFilterWidget from './piece_list_toolbar_filter_widget'; import PieceListToolbarOrderWidget from './piece_list_toolbar_order_widget'; import SearchBar from '../search_bar'; +import AppConstants from '../../constants/application_constants'; + let PieceListToolbar = React.createClass({ propTypes: { @@ -76,7 +78,7 @@ let PieceListToolbar = React.createClass({ className="pull-right search-bar ascribe-input-glyph" searchFor={searchFor} searchQuery={searchQuery} - threshold={500}/> + threshold={AppConstants.searchThreshold}/> {this.getOrderWidget()} {this.getFilterWidget()} diff --git a/js/components/search_bar.js b/js/components/search_bar.js index 642094b3..365d6485 100644 --- a/js/components/search_bar.js +++ b/js/components/search_bar.js @@ -12,12 +12,16 @@ const { update } = React.addons; const SearchBar = React.createClass({ propTypes: { + // a function that accepts a string as a search query and updates the + // propagated `searchQuery` after successfully retrieving the + // request from the server searchFor: func.isRequired, searchQuery: string.isRequired, className: string, - // in milliseconds + // the number of milliseconds the component + // should wait before requesting search results from the server threshold: number.isRequired }, @@ -25,7 +29,7 @@ const SearchBar = React.createClass({ return { timers: [], searchQuery: '', - searching: false + loading: false }; }, @@ -33,16 +37,44 @@ const SearchBar = React.createClass({ const searchQueryProps = this.props.searchQuery; const searchQueryPrevProps = prevProps.searchQuery; const searchQueryState = this.state.searchQuery; - const { searching } = this.state; + const { loading } = this.state; - if(searching && (searchQueryProps && searchQueryState && searchQueryProps === searchQueryState || !searchQueryPrevProps && searchQueryProps === searchQueryState)) { - this.setState({ searching: false }); + /** + * 1. Condition: `loading` must be true, which implies that `evaluateTimer`, + * has already been called + * + * AND + * + * 2. Condition: `searchQueryProps` and `searchQueryState` are true and equal + * (which means that the search query has been propagated to the inner + * fetch method of `fetchPieceList`, which in turn means that a fetch + * has completed) + * + * OR + * + * 3. Condition: `searchQueryProps` and `searchQueryState` can be any value (`true` or + * `false`, as long as they're equal). This case only occurs when the user + * has entered a `searchQuery` and deletes the query in one go, reseting + * `searchQueryProps` to empty string ('' === false) again. + */ + + const firstCondition = !!loading; + const secondCondition = searchQueryProps && searchQueryState && searchQueryProps === searchQueryState; + const thirdCondition = !searchQueryPrevProps && searchQueryProps === searchQueryState; + + if(firstCondition && (secondCondition || thirdCondition)) { + this.setState({ loading: false }); } }, startTimers(searchQuery) { const { timers } = this.state; const { threshold } = this.props; + + // the timer waits for the specified threshold time in milliseconds + // and then calls `evaluateTimer`, that checks if another letter + // has been added to the query (by checking if there are newer + // timers on the stack aka. `this.state.timers`) const timer = { searchQuery, cb: setTimeout(this.evaluateTimer(timers.length, searchQuery), threshold) @@ -56,9 +88,14 @@ const SearchBar = React.createClass({ return () => { const { timers } = this.state; + // If there have been no timers added to `this.state.timers`, + // while the `threshold` was passed, we start loading + // by querying the server. if(timers.length <= timerIndex + 1) { - // clean the timers array - this.setState({ timers: [], searching: true }, () => { + // However, we're doing that only after setting `this.state.loading` + // to `true`, as we want to display a little spinner while loading. + // We also clean the now worthless `timers` array. + this.setState({ timers: [], loading: true }, () => { // search for the query this.props.searchFor(searchQuery); }); @@ -67,6 +104,9 @@ const SearchBar = React.createClass({ }, handleChange({ target: { value }}) { + // On each letter entry we're updating the state of the component + // and start a timer, which we're also pushing to the state + // of the component this.startTimers(value); this.setState({ searchQuery: value }); }, @@ -74,9 +114,9 @@ const SearchBar = React.createClass({ render() { let searchIcon = ; const { className } = this.props; - const { searching } = this.state; + const { loading } = this.state; - if(searching) { + if(loading) { searchIcon = ; } diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index c74fdce9..0271dda7 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -78,7 +78,8 @@ let constants = { 'copyrightAssociations': ['ARS', 'DACS', 'Bildkunst', 'Pictoright', 'SODRAC', 'Copyright Agency/Viscopy', 'SAVA', 'Bildrecht GmbH', 'SABAM', 'AUTVIS', 'CREAIMAGEN', 'SONECA', 'Copydan', 'EAU', 'Kuvasto', 'GCA', 'HUNGART', 'IVARO', 'SIAE', 'JASPAR-SPDA', 'AKKA/LAA', 'LATGA-A', 'SOMAAP', 'ARTEGESTION', 'CARIER', 'BONO', 'APSAV', - 'SPA', 'GESTOR', 'VISaRTA', 'RAO', 'LITA', 'DALRO', 'VeGaP', 'BUS', 'ProLitteris', 'AGADU', 'AUTORARTE', 'BUBEDRA', 'BBDA', 'BCDA', 'BURIDA', 'ADAVIS', 'BSDA'] + 'SPA', 'GESTOR', 'VISaRTA', 'RAO', 'LITA', 'DALRO', 'VeGaP', 'BUS', 'ProLitteris', 'AGADU', 'AUTORARTE', 'BUBEDRA', 'BBDA', 'BCDA', 'BURIDA', 'ADAVIS', 'BSDA'], + 'searchThreshold': 500 }; export default constants; From cc089fe92b02079ccc3867effa4ebcc630e6e89c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 12 Oct 2015 17:12:10 +0200 Subject: [PATCH 5/8] Add parenthesis --- js/components/search_bar.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/components/search_bar.js b/js/components/search_bar.js index 365d6485..82b96196 100644 --- a/js/components/search_bar.js +++ b/js/components/search_bar.js @@ -45,6 +45,7 @@ const SearchBar = React.createClass({ * * AND * + * ( * 2. Condition: `searchQueryProps` and `searchQueryState` are true and equal * (which means that the search query has been propagated to the inner * fetch method of `fetchPieceList`, which in turn means that a fetch @@ -56,6 +57,7 @@ const SearchBar = React.createClass({ * `false`, as long as they're equal). This case only occurs when the user * has entered a `searchQuery` and deletes the query in one go, reseting * `searchQueryProps` to empty string ('' === false) again. + * ) */ const firstCondition = !!loading; From c48c7dc4bd27b9e04ecb23210659f55ba8ff5ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 12 Oct 2015 17:33:07 +0200 Subject: [PATCH 6/8] Simplify SearchBar timing functionality --- js/components/search_bar.js | 50 ++++++++++++++----------------------- 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/js/components/search_bar.js b/js/components/search_bar.js index 82b96196..ba6f4ea1 100644 --- a/js/components/search_bar.js +++ b/js/components/search_bar.js @@ -1,6 +1,6 @@ 'use strict'; -import React from 'react/addons'; +import React from 'react'; import Input from 'react-bootstrap/lib/Input'; import Glyphicon from 'react-bootstrap/lib/Glyphicon'; @@ -8,7 +8,6 @@ import { getLangText } from '../utils/lang_utils'; const { func, string, number } = React.PropTypes; -const { update } = React.addons; const SearchBar = React.createClass({ propTypes: { @@ -27,7 +26,7 @@ const SearchBar = React.createClass({ getInitialState() { return { - timers: [], + timer: null, searchQuery: '', loading: false }; @@ -69,39 +68,28 @@ const SearchBar = React.createClass({ } }, - startTimers(searchQuery) { - const { timers } = this.state; + startTimer(searchQuery) { + const { timer } = this.state; const { threshold } = this.props; - // the timer waits for the specified threshold time in milliseconds - // and then calls `evaluateTimer`, that checks if another letter - // has been added to the query (by checking if there are newer - // timers on the stack aka. `this.state.timers`) - const timer = { - searchQuery, - cb: setTimeout(this.evaluateTimer(timers.length, searchQuery), threshold) - }; + // The timer waits for the specified threshold time in milliseconds + // and then calls `evaluateTimer`. + // If another letter has been called in the mean time (timespan < `threshold`), + // the present timer gets cleared and a new one is added to `this.state`. + // This means that `evaluateTimer`, will only be called when the threshold has actually + // passed, + clearTimeout(timer); // apparently `clearTimeout` can be called with null, without throwing errors + const newTimer = setTimeout(this.evaluateTimer(searchQuery), threshold); - const newTimers = update(timers, {$push: [timer]}); - this.setState({ timers: newTimers }); + this.setState({ timer: newTimer }); }, - evaluateTimer(timerIndex, searchQuery) { + evaluateTimer(searchQuery) { return () => { - const { timers } = this.state; - - // If there have been no timers added to `this.state.timers`, - // while the `threshold` was passed, we start loading - // by querying the server. - if(timers.length <= timerIndex + 1) { - // However, we're doing that only after setting `this.state.loading` - // to `true`, as we want to display a little spinner while loading. - // We also clean the now worthless `timers` array. - this.setState({ timers: [], loading: true }, () => { - // search for the query - this.props.searchFor(searchQuery); - }); - } + this.setState({ timer: null, loading: true }, () => { + // search for the query + this.props.searchFor(searchQuery); + }); }; }, @@ -109,7 +97,7 @@ const SearchBar = React.createClass({ // On each letter entry we're updating the state of the component // and start a timer, which we're also pushing to the state // of the component - this.startTimers(value); + this.startTimer(value); this.setState({ searchQuery: value }); }, From ea40181805a05e7dfba7e3cfa6816f7f78d949a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 13 Oct 2015 17:28:10 +0200 Subject: [PATCH 7/8] add 'clear search' dialog to AccordionList and implement functionality in SearchBar --- .../ascribe_accordion_list/accordion_list.js | 38 ++++++++++++++++--- js/components/piece_list.js | 1 + js/components/search_bar.js | 14 +++++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list.js b/js/components/ascribe_accordion_list/accordion_list.js index fe300702..c488a3d8 100644 --- a/js/components/ascribe_accordion_list/accordion_list.js +++ b/js/components/ascribe_accordion_list/accordion_list.js @@ -9,21 +9,49 @@ let AccordionList = React.createClass({ className: React.PropTypes.string, children: React.PropTypes.arrayOf(React.PropTypes.element).isRequired, loadingElement: React.PropTypes.element, - count: React.PropTypes.number + count: React.PropTypes.number, + itemList: React.PropTypes.arrayOf(React.PropTypes.object), + search: React.PropTypes.string, + searchFor: React.PropTypes.func }, - + + clearSearch() { + this.props.searchFor(''); + }, + render() { + const { search } = this.props; + if(this.props.itemList && this.props.itemList.length > 0) { return (
{this.props.children}
); - } else if(this.props.count === 0) { + } else if(this.props.count === 0 && !search) { return (
-

{getLangText('We could not find any works related to you...')}

-

{getLangText('To register one, click')} {getLangText('here')}!

+

+ {getLangText('We could not find any works related to you...')} +

+

+ {getLangText('To register one, click')} + {getLangText('here')}! +

+
+ ); + } else if(this.props.count === 0 && search) { + return ( +
+

+ {getLangText('We could not find any works related to you...')} +

+

+ {getLangText('You\'re filtering by the search keyword: \'%s\' ', search)} +

+

+ +

); } else { diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 908c2821..05557418 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -178,6 +178,7 @@ let PieceList = React.createClass({ orderBy={this.state.orderBy} orderAsc={this.state.orderAsc} search={this.state.search} + searchFor={this.searchFor} page={this.state.page} pageSize={this.state.pageSize} loadingElement={loadingElement}> diff --git a/js/components/search_bar.js b/js/components/search_bar.js index ba6f4ea1..d5b5cefe 100644 --- a/js/components/search_bar.js +++ b/js/components/search_bar.js @@ -68,6 +68,19 @@ const SearchBar = React.createClass({ } }, + componentWillReceiveProps(nextProps) { + /** + * This enables the `PieceListStore` to override the state + * of that component in case someone is changing the `searchQuery` on + * another component. + * + * Like how it's being done in the 'Clear search' dialog. + */ + if(this.props.searchQuery !== nextProps.searchQuery) { + this.setState({ searchQuery: nextProps.searchQuery }); + } + }, + startTimer(searchQuery) { const { timer } = this.state; const { threshold } = this.props; @@ -114,6 +127,7 @@ const SearchBar = React.createClass({ From 3321379a8f6c40f20dff9b59f9b85640d707eb11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 13 Oct 2015 17:30:49 +0200 Subject: [PATCH 8/8] bug fix for going to a piece when in a search --- js/components/search_bar.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/components/search_bar.js b/js/components/search_bar.js index d5b5cefe..e8382489 100644 --- a/js/components/search_bar.js +++ b/js/components/search_bar.js @@ -76,7 +76,7 @@ const SearchBar = React.createClass({ * * Like how it's being done in the 'Clear search' dialog. */ - if(this.props.searchQuery !== nextProps.searchQuery) { + if(this.props.searchQuery !== nextProps.searchQuery || !this.state.searchQuery) { this.setState({ searchQuery: nextProps.searchQuery }); } }, @@ -117,7 +117,7 @@ const SearchBar = React.createClass({ render() { let searchIcon = ; const { className } = this.props; - const { loading } = this.state; + const { loading, searchQuery } = this.state; if(loading) { searchIcon = ; @@ -127,7 +127,7 @@ const SearchBar = React.createClass({