Merge pull request #484 from lucaas/fix-483-autocomplete-unintuitive-filter-behaviour-with-multiple-false

Fix #483: Autocomplete unintuitive filter behavior with multiple=false
old
Javi Velasco 2016-05-21 19:11:36 +02:00
commit 563868b90e
4 changed files with 64 additions and 7 deletions

View File

@ -22,6 +22,7 @@ class Autocomplete extends React.Component {
multiple: React.PropTypes.bool,
onChange: React.PropTypes.func,
selectedPosition: React.PropTypes.oneOf(['above', 'below']),
showSuggestionsWhenValueIsSet: React.PropTypes.bool,
source: React.PropTypes.any,
value: React.PropTypes.any
};
@ -31,12 +32,14 @@ class Autocomplete extends React.Component {
direction: 'auto',
selectedPosition: 'above',
multiple: true,
showSuggestionsWhenValueIsSet: false,
source: {}
};
state = {
direction: this.props.direction,
focus: false,
showAllSuggestions: this.props.showSuggestionsWhenValueIsSet,
query: this.query(this.props.value)
};
@ -61,7 +64,10 @@ class Autocomplete extends React.Component {
const key = this.props.multiple ? keys : keys[0];
const query = this.query(key);
if (this.props.onChange) this.props.onChange(key, event);
this.setState({ focus: false, query }, () => { this.refs.input.blur(); });
this.setState(
{focus: false, query, showAllSuggestions: this.props.showSuggestionsWhenValueIsSet},
() => { this.refs.input.blur(); }
);
};
handleQueryBlur = () => {
@ -69,7 +75,7 @@ class Autocomplete extends React.Component {
};
handleQueryChange = (value) => {
this.setState({query: value});
this.setState({query: value, showAllSuggestions: false});
};
handleQueryFocus = () => {
@ -77,6 +83,18 @@ class Autocomplete extends React.Component {
this.setState({active: '', focus: true});
};
handleQueryKeyDown = (event) => {
// Clear query when pressing backspace and showing all suggestions.
const shouldClearQuery = (
event.which === 8
&& this.props.showSuggestionsWhenValueIsSet
&& this.state.showAllSuggestions
);
if (shouldClearQuery) {
this.setState({query: ''});
}
};
handleQueryKeyUp = (event) => {
if (event.which === 13 && this.state.active) this.select(this.state.active, event);
if (event.which === 27) this.refs.input.blur();
@ -109,15 +127,32 @@ class Autocomplete extends React.Component {
}
suggestions () {
const suggest = new Map();
let suggest = new Map();
const query = this.state.query.toLowerCase().trim() || '';
const values = this.values();
for (const [key, value] of this.source()) {
if (value.toLowerCase().trim().startsWith(query)
&& (!values.has(key) || !this.props.multiple)) {
suggest.set(key, value);
const source = this.source();
// Suggest any non-set value which matches the query
if (this.props.multiple) {
for (const [key, value] of source) {
if (!values.has(key) && value.toLowerCase().trim().startsWith(query)) {
suggest.set(key, value);
}
}
// When multiple is false, suggest any value which matches the query if showAllSuggestions is false
} else if (query && !this.state.showAllSuggestions) {
for (const [key, value] of source) {
if (value.toLowerCase().trim().startsWith(query)) {
suggest.set(key, value);
}
}
// When multiple is false, suggest all values when showAllSuggestions is true
} else {
suggest = source;
}
return suggest;
}
@ -209,6 +244,7 @@ class Autocomplete extends React.Component {
onBlur={this.handleQueryBlur}
onChange={this.handleQueryChange}
onFocus={this.handleQueryFocus}
onKeyDown={this.handleQueryKeyDown}
onKeyUp={this.handleQueryKeyUp}
value={this.state.query}
/>

View File

@ -50,6 +50,7 @@ class AutocompleteTest extends React.Component {
| `onChange` | `Function` | | Callback function that is fired when the components's value changes.|
| `source` | `Object` or `Array` | | Object of key/values or array representing all items suggested. |
| `selectedPosition` | `String` | `above` | Determines if the selected list is shown above or below input. It can be `above` or `below`. |
| `showSuggestionsWhenValueIsSet` | `Bool` | `false` | If true, the list of suggestions will not be filtered when a value is selected, until the query is modified. |
| `value` | `String` or `Array` | | Value or array of values currently selected component.|
Additional properties will be passed to the Input Component so you can use `hint`, `name` ... etc.

5
react-toolbox.d.ts vendored
View File

@ -189,6 +189,11 @@ declare namespace __RT {
* Object of key/values or array representing all items suggested.
*/
source: Object | Array<any>,
/**
* If true, the list of suggestions will not be filtered when a value is selected, until the query is modified.
* @default false
*/
showSuggestionsWhenValueIsSet?: boolean,
/**
* Type of the input element. It can be a valid HTML5 input type
* @default text

View File

@ -7,6 +7,7 @@ const countriesObject = {'ES-es': 'Spain', 'TH-th': 'Thailand', 'EN-gb': 'Englan
class AutocompleteTest extends React.Component {
state = {
simple: 'Spain',
simpleShowAll: 'England',
multiple: ['ES-es', 'TH-th']
};
@ -18,6 +19,10 @@ class AutocompleteTest extends React.Component {
this.setState({simple: value});
};
handleSimpleShowAllChange = (value) => {
this.setState({simpleShowAll: value});
};
render () {
return (
<section>
@ -39,6 +44,16 @@ class AutocompleteTest extends React.Component {
source={countriesArray}
value={this.state.simple}
/>
<Autocomplete
label="Choose a country (showing all suggestions)"
hint="Elements up to you..."
multiple={false}
onChange={this.handleSimpleShowAllChange}
source={countriesArray}
value={this.state.simpleShowAll}
showSuggestionsWhenValueIsSet
/>
</section>
);
}