diff --git a/src/components/input/autocomplete-select/consult.js b/src/components/input/autocomplete-select/consult.js
index 79ecd4828..5a9491f5a 100644
--- a/src/components/input/autocomplete-select/consult.js
+++ b/src/components/input/autocomplete-select/consult.js
@@ -1,14 +1,34 @@
-import React, { Component } from 'react';
+import React, { Component, PropTypes } from 'react';
import ComponentBaseBehaviour from '../../../behaviours/component-base';
+@ComponentBaseBehaviour
/**
* Autcomplete select component consultation view.
*/
-@ComponentBaseBehaviour
class AutocompleteSelectConsult extends Component {
+ /** DisplayName. */
static displayName = 'AutocompleteSelectConsult';
+ /** PropTypes. */
+ static propTypes = {
+ keyName: PropTypes.string,
+ keyResolver: PropTypes.func.isRequired,
+ label: PropTypes.string.isRequired,
+ labelName: PropTypes.string,
+ name: PropTypes.string.isRequired,
+ type: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
+ wholeItem: PropTypes.bool
+ };
+
+ /** DefaultProps. */
+ static defaultProps = {
+ keyName: 'key',
+ labelName: 'label',
+ wholeItem: false
+ };
+
/** Initial state. */
state = {};
@@ -29,9 +49,10 @@ class AutocompleteSelectConsult extends Component {
* @param {string} value value.
*/
_callKeyResolver(value) {
- const { keyResolver } = this.props;
+ const { keyResolver, keyName, wholeItem } = this.props;
if (keyResolver && value !== undefined && value !== null) {
- keyResolver(value).then(label => {
+ const key = wholeItem ? value[keyName] : value;
+ keyResolver(key).then(label => {
this.setState({ resolvedLabel: label });
}).catch(err => { console.error(err.message); });
}
@@ -39,8 +60,8 @@ class AutocompleteSelectConsult extends Component {
/** @inheritdoc */
render() {
- const { label, name, type, value } = this.props;
- const { resolvedLabel = value } = this.state;
+ const { label, name, type, value, wholeItem, labelName } = this.props;
+ const { resolvedLabel = wholeItem ? value[labelName] : value } = this.state;
return (
{
- this.setState({ inputValue, fromKeyResolver: true });
- }).catch(error => this.setState({ customError: error.message }));
+ if (value !== undefined && value !== null) {
+ this._setValue(value);
}
document.addEventListener('click', this._handleDocumentClick);
@@ -93,12 +99,11 @@ class AutocompleteSelectEdit extends Component {
/** @inheritdoc */
componentWillReceiveProps({ value, customError, error }) {
- const { keyResolver } = this.props;
+ const { labelName, wholeItem } = this.props;
if (value !== this.props.value && value !== undefined && value !== null) { // value is defined, call the keyResolver to get the associated label
- this.setState({ inputValue: value, customError }, () => keyResolver(value).then(inputValue => {
- this.setState({ inputValue, fromKeyResolver: true });
- }).catch(error => this.setState({ customError: error.message })));
+ const inputValue = wholeItem ? value[labelName] : value;
+ this.setState({ inputValue, customError }, () => this._setValue(value));
} else if (customError !== this.props.customError) {
this.setState({ customError });
}
@@ -126,22 +131,39 @@ class AutocompleteSelectEdit extends Component {
document.removeEventListener('click', this._handleDocumentClick);
}
+ /**
+ * Set value.
+ * @param {object|string} value Value.
+ */
+ _setValue(value) {
+ const { keyResolver, labelName, wholeItem } = this.props;
+
+ if (wholeItem) {
+ this.setState({ inputValue: value[labelName], fromKeyResolver: true });
+ } else {
+ keyResolver(value).then(inputValue => {
+ this.setState({ inputValue, fromKeyResolver: true });
+ }).catch(error => this.setState({ customError: error.message }));
+ }
+ }
+
/**
* Get value.
* @returns {string} value.
*/
getValue() {
- const { labelName, keyName, value } = this.props;
+ const { labelName, value, wholeItem } = this.props;
const { inputValue, selected, options, fromKeyResolver } = this.state;
- const resolvedLabel = options.get(selected);
+ const item = options.get(selected) || {};
+ const resolvedLabel = item[labelName];
if (inputValue === '') { // The user cleared the field, return a null
return null;
- } else if (fromKeyResolver) { // Value was received from the keyResolver, give it firectly
+ } else if (fromKeyResolver) { // Value was received from the keyResolver, give it directly
return value;
} else if (resolvedLabel !== inputValue && selected !== inputValue) { // The user typed something without selecting any option, return a null
return null;
} else { // The user selected an option (or no value was provided), return it
- return selected || null;
+ return wholeItem ? item : selected || null;
}
}
@@ -162,7 +184,7 @@ class AutocompleteSelectEdit extends Component {
});
}
}
- };
+ }
/**
* Handle query change.
@@ -172,28 +194,29 @@ class AutocompleteSelectEdit extends Component {
if (value === '') { // the user cleared the input, don't call the querySearcher
const { onChange } = this.props;
this.setState({ inputValue: value, fromKeyResolver: false });
- if (onChange) onChange(null);
+ if (onChange) {
+ onChange(null);
+ }
} else {
this.setState({ inputValue: value, fromKeyResolver: false, isLoading: true });
this._debouncedQuerySearcher(value);
}
- };
+ }
/**
* Query searcher.
* @param {string} value value.
*/
_querySearcher(value) {
- const { querySearcher, keyName, labelName } = this.props;
+ const { querySearcher, keyName } = this.props;
querySearcher(value).then(({ data, totalCount }) => {
- // TODO handle the incomplete option list case
const options = new Map();
data.forEach(item => {
- options.set(item[keyName], item[labelName]);
+ options.set(item[keyName], item);
});
this.setState({ options, isLoading: false, totalCount });
}).catch(error => this.setState({ customError: error.message }));
- };
+ }
/**
* Handle query field focus.
@@ -204,7 +227,7 @@ class AutocompleteSelectEdit extends Component {
this.props.onFocus.call(this);
}
this.setState({ active: '', focus: true });
- };
+ }
/**
* Handle query field key down.
@@ -235,7 +258,7 @@ class AutocompleteSelectEdit extends Component {
}
this.setState({ active: optionKeys[newIndex] });
}
- };
+ }
/**
* Handle suggestion hover.
@@ -243,7 +266,7 @@ class AutocompleteSelectEdit extends Component {
*/
_handleSuggestionHover(key) {
this.setState({ active: key });
- };
+ }
/**
* Handle selection of result.
@@ -251,8 +274,9 @@ class AutocompleteSelectEdit extends Component {
*/
_select(key) {
const { options } = this.state;
- const { onChange } = this.props;
- const resolvedLabel = options.get(key) || '';
+ const { onChange, labelName, wholeItem } = this.props;
+ const item = options.get(key) || {};
+ const resolvedLabel = item[labelName] || '';
this.refs.htmlInput.blur();
let newState = { inputValue: this.i18n(resolvedLabel), selected: key, focus: false };
if (this.props.onSelectClear === true) {
@@ -260,7 +284,7 @@ class AutocompleteSelectEdit extends Component {
}
this.setState(newState, () => {
if (onChange) {
- onChange(key);
+ onChange(wholeItem ? item : key);
}
});
}
@@ -270,9 +294,10 @@ class AutocompleteSelectEdit extends Component {
* @returns {JSXElement} options.
*/
_renderOptions() {
+ const { labelName } = this.props;
const { active, options, focus } = this.state;
const renderedOptions = [];
- for (let [key, value] of options) {
+ for (let [key, item] of options) {
const isActive = active === key;
renderedOptions.push(
this._select(key)}
onMouseOver={() => this._handleSuggestionHover(key)}
>
- {this.i18n(value)}
+ {this.i18n(item[labelName])}
);
}
@@ -292,7 +317,7 @@ class AutocompleteSelectEdit extends Component {
{renderedOptions}
);
- };
+ }
/** @inheritdoc */
render() {
diff --git a/src/components/input/autocomplete-select/field.js b/src/components/input/autocomplete-select/field.js
index 81602a0fb..15d5b9822 100644
--- a/src/components/input/autocomplete-select/field.js
+++ b/src/components/input/autocomplete-select/field.js
@@ -1,7 +1,7 @@
import React, { Component, PropTypes } from 'react';
import AutocompleteSelectEdit from './edit';
import AutocompleteSelectConsult from './consult';
-import translation from 'focus-core/translation';
+import { translate } from 'focus-core/translation';
/**
* Autocomplete select component.
@@ -15,6 +15,7 @@ class AutocompleteSelectField extends Component {
isEdit: PropTypes.bool.isRequired,
keyResolver: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
querySearcher: PropTypes.func.isRequired
};
@@ -48,15 +49,15 @@ class AutocompleteSelectField extends Component {
} else {
return value;
}
- };
+ }
/**
* Handle bad input and display error message.
* @param {string} value value.
*/
_handleAutocompleteBadInput(value) {
- this.setState({ customError: translation.translate('autocomplete.error.badInput', { value }) })
- };
+ this.setState({ customError: translate('autocomplete.error.badInput', { value }) })
+ }
/**
* Handle for value selection.
@@ -69,10 +70,11 @@ class AutocompleteSelectField extends Component {
onChange(value);
}
});
- };
+ }
/**
* Renders component in edition mode.
+ * @returns {JSXElement} Edit component.
*/
_renderEdit() {
const { customError } = this.state;
@@ -85,10 +87,11 @@ class AutocompleteSelectField extends Component {
{...this.props}
/>
);
- };
+ }
/**
* Renders component in consultation mode.
+ * @returns {JSXElement} Consult component.
*/
_renderConsult() {
return (
@@ -96,7 +99,7 @@ class AutocompleteSelectField extends Component {
{...this.props}
/>
);
- };
+ }
/** @inheritdoc */
render() {