Last active
January 18, 2017 16:20
-
-
Save gram7gram/322d9a8415683eadc9f56ad215a3c0a7 to your computer and use it in GitHub Desktop.
Stateless React Select with redux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
import '../../../node_modules/react-select/dist/react-select.css'; | |
import React from 'react'; | |
import Select from 'react-select'; | |
import {objectValues} from '../../Survey/utils'; | |
import keyBy from 'lodash/keyBy'; | |
import trans from '../translator'; | |
class StatelessSelect extends React.Component { | |
constructor() { | |
super() | |
this.loadItems = this.loadItems.bind(this) | |
this.setItems = this.setItems.bind(this) | |
} | |
componentDidMount() { | |
this.props.preload && this.props.dispatch(this.props.fetchAction()) | |
} | |
setItems(options) { | |
let items = false; | |
let selectedModels = false; | |
if (options) { | |
if (this.props.multi) { | |
items = options.map(option => this.props.collection.find(obj => obj.id === option.value)) | |
.filter(item => item && item.id > 0); | |
selectedModels = options.map(option => this.props.selectedModels.find(obj => obj.id === option.value)) | |
.filter(item => item && item.id > 0) | |
items = objectValues(keyBy(items.concat(selectedModels), 'id')) | |
} else { | |
items = this.props.collection.find(obj => obj.id === options.value); | |
} | |
} | |
this.props.dispatch(this.props.changeAction(items)) | |
} | |
loadItems(search) { | |
if (this.props.isLoading) return; | |
if (search.length < this.props.minimumInputLength) return; | |
if (search === this.props.previousSearch) return; | |
if (!this.props.isLoaded) { | |
this.props.dispatch(this.props.fetchAction({filter: {search}})) | |
return; | |
} | |
search = search.trim().toUpperCase() | |
if (this.props.isLocal) { | |
const items = this.props.allOptions.filter(obj => obj.label.toUpperCase().indexOf(search) !== -1) | |
this.props.dispatch(this.props.filterAction(items, search, this.props.previousSearch)) | |
} else { | |
this.props.dispatch(this.props.fetchAction({filter: {search}})) | |
} | |
} | |
render() { | |
return <Select | |
value={this.props.selectedOptions} | |
options={this.props.filteredOptions} | |
onChange={this.setItems} | |
onInputChange={this.loadItems} | |
{...this.props} | |
/> | |
} | |
} | |
StatelessSelect.propTypes = { | |
/** Access to store */ | |
dispatch: React.PropTypes.func.isRequired, | |
/** Dispatch fetch collection on component mount */ | |
fetchAction: React.PropTypes.func.isRequired, | |
/** Dispatch filter collection on input change */ | |
filterAction: React.PropTypes.func.isRequired, | |
/** Dispatch on change */ | |
changeAction: React.PropTypes.func.isRequired, | |
/** Select-friendly collection: [{label: '', value: ''}] */ | |
allOptions: React.PropTypes.array, | |
/** Raw collection. Not select-friendly */ | |
collection: React.PropTypes.array, | |
/** Select-friendly collection, that match input text: [{label: '', value: ''}] */ | |
filteredOptions: React.PropTypes.array, | |
/** Select-friendly collection, that was selected: [{label: '', value: ''}] */ | |
selectedOptions: React.PropTypes.any, | |
/** Raw collection, that was selected. Not select-friendly */ | |
selectedModels: React.PropTypes.any, | |
/** Collection will be filtered, when search length is same or greater then this value */ | |
minimumInputLength: React.PropTypes.number, | |
/** Previous search text */ | |
previousSearch: React.PropTypes.string, | |
/** Fetch collection on component mount */ | |
preload: React.PropTypes.any, | |
/** Should collection be loaded onle ONCE? */ | |
isLocal: React.PropTypes.any, | |
} | |
StatelessSelect.defaultProps = { | |
minimumInputLength: 2, | |
preload: false, | |
isLocal: false, | |
noResultsText: trans.ru.noResultsText, | |
searchPromptText: trans.ru.searchPromptText, | |
placeholder: trans.ru.placeholder, | |
clearAllText: trans.ru.clearAllText, | |
clearValueText: trans.ru.clearValueText, | |
} | |
export default StatelessSelect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fetchOrganizations from '../../actions/FetchOrganizations/Action' | |
import filterOrganizations from '../../actions/FilterOrganizations/Action' | |
import changeOrganizations from '../../actions/ChangeOrganizations/Action' | |
... | |
render() { | |
return ( | |
<FormGroup validationState={!Validator.isValid && errors.customer ? "error" : null}> | |
<label>{trans.ru.orgCustomer}</label> | |
<StatelessSelect | |
preload={this.props.Customers.collection.length === 0 && !this.props.Customers.isLoading} | |
isLocal={true} | |
dispatch={this.props.dispatch} | |
fetchAction={fetchOrganizations} | |
filterAction={filterOrganizations} | |
changeAction={changeOrganizations} | |
{...this.props.Customers} | |
selectedModels={model.customer} | |
selectedOptions={model.customer ? { | |
value: model.customer.id, | |
label: getOrganizationLabel(model.customer) | |
} : null} | |
/> | |
{!Validator.isValid && errors.customer | |
? <HelpBlock>{errors.customer.message}</HelpBlock> | |
: null} | |
</FormGroup> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment