Please have a look at this code, When I click on the drop down it shows 10 values, If I select any value from these values it get selected.
But when i search in drop down for example if I type test. It then shows 10 values matching the given string ( test ). But if i try to select any value from the new data set ( which matched the 'test' input ) value do not get selected.
getOptions = (input: string, callback: Function) => {
this.props.action(
input,
/* callback */
(res: Object): void => {
if ( res && res.data ) {
callback(null, { options: res.data });
} else {
callback([]);
}
}
);
};
render() {
const { name, label, value, multi, placeholder, onChange } = this.props;
return (<Async
name={name}
label={label}
value={value}
placeholder={placeholder}
autoload
loadOptions={this.getOptions}
onChange={onChange}
async
multi={multi}
/>);
}
@saadbinsaeed Doc just dont get updated yet. i will do this tommorow. u need to pass {value: '', label: ''} instead of string
@gen1321 where should it be passed? In value
?
yep, value
should be { value: '...', label: '...' }
object. Is there any possibility to get current options?
please update docs or update this issue
Check the last comment here. Solved the same issue for me
what about multiple values?
I just spend the last couple of hours trying to implement this async multiselect with redux form. I needed to get just the value from the selection sent to redux form (or comma separated string of values rather), but I couldn't use that to display the select option on screen because Async only displays the selected options when the value you feed it is an array of objects like... [{value: '', label: ''}]. The simpleValue prop doesn't seem to play nicely with the Async component either which is how I'm working with the Select component. It will output simpleValue onChange, but you can't use that as a value to display the selections. Anyhow this is my component...
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Async } from 'react-select';
import _ from 'lodash';
import { client } from '../../../actions/client';
class ReduxFormMultiSelect extends Component {
constructor(props) {
super(props);
this.state = {
values: []
};
this.handleInputChange = this.handleInputChange.bind(this);
this.getOptions = this.getOptions.bind(this);
}
getOptions(input) {
if (!input) {
return Promise.resolve({ options: [] });
}
return client.get(`${this.props.optionsEndpoint}?q=${input}&select=true`)
.then(response => (
{ options: response.data }
));
}
handleInputChange(values) {
// send selection options array to state
this.setState({ ...this.state, values });
// pull selected values into array
const vals = _.map(values, 'value');
// join array into comma separated string for redux form
this.props.onChange(vals.join(','));
}
render() {
const { input, className } = this.props;
return (
<Async
{...input}
placeholder={'Select one or more...'}
className={className}
multi
// simpleValue
disabled={false}
onBlurResetsInput={false}
loadOptions={this.getOptions}
onChange={this.handleInputChange}
value={this.state.values}
/>
);
}
}
export default ReduxFormMultiSelect;
ReduxFormMultiSelect.propTypes = {
optionsEndpoint: PropTypes.string,
input: PropTypes.object,
onChange: PropTypes.func,
onBlur: PropTypes.func
};
I am passing { value: '...', label: '...' }
but it does not seem to display the selected value in the box. here is my component. when i select an item my state variable holds {value: "3", label: "ACG_242-0_non_working_flows_to_test_-Template-v6.3.xls"}
which gets passed onto the Async
component but it does not display the value even though it is in the list
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import FontAwesome from 'react-fontawesome';
import { isServiceName, isServiceRef } from '../../scripts/validation';
import {
fetchExemptionType,
fetchMarkets,
fetchServiceDomains,
fetchServicesList,
fetchExemptionsForCommsmatrix,
fetchSecurityEngineerList,
fetchBusinessPriorityList
} from '../../actions/security';
import { fetchCommsmatricesByService } from '../../actions/commsmatrices';
import axios from 'axios';
import { Field, reduxForm } from 'redux-form';
import PropTypes from 'prop-types';
import { Select, Async } from "react-select";
import 'react-select/dist/react-select.css';
import { Checkbox } from 'react-bootstrap';
import {
BootstrapTable,
TableHeaderColumn
} from 'react-bootstrap-table';
import 'react-bootstrap-table/dist/react-bootstrap-table-all.min.css';
const ASYNC_DELAY = 500;
class SecurityExemptionsNew extends Component {
constructor(props) {
super(props);
this.handleSaveBtnClick = this.handleSaveBtnClick.bind(this);
this.handleShowError = this.handleShowError.bind(this);
this.initData = this.initData.bind(this);
this.renderSelectField = this.renderSelectField.bind(this);
this.renderTextField = this.renderTextField.bind(this);
this.updateCommsMatrix = this.updateCommsMatrix.bind(this);
this.renderSelect2Field = this.renderSelect2Field.bind(this);
this.clearValue = this.clearValue.bind(this);
this.updateValue = this.updateValue.bind(this);
this.getCommsmatrices = this.getCommsmatrices.bind(this);
this.fnToggleCheckboxes = this.fnToggleCheckboxes.bind(this);
this.handleCheckedValues = this.handleCheckedValues.bind(this);
this.meta = {
title: 'Request Exemption',
description: 'This section allows you to request an exemption'
};
this.passMetaBack = this.passMetaBack.bind(this);
this.runOnce = false;
this.state = {
loaded: false,
isLoading: true,
//country: 'AU',
//disabled: false,
searchable: true,
selectValue: { value: '0', label: 'All'},
clearable: true,
rtl: false,
options: [
{ value: '0', label: 'All'}
],
toggleChecked: true,
};
this.exemptionType = {};
this.markets = {};
this.serviceDomain = {};
this.servicesList = {};
this.matrices = {};
this.securityEngineerList = {};
this.businessPriority = {}
this.tableOptions = {
paginationShowsTotal: false,
sizePerPageList: [ {
text: '10', value: 10
}, {
text: '50', value: 50
}, {
text: '100', value: 100
}
],
};
this.checkedValues = [];
}
passMetaBack = () => {
this.props.passMetaBack(this.meta);
};
handleShowError(errorMsg) {
this.props.handleShowError({ show: true, errorMsg: errorMsg });
}
handleSaveBtnClick = () => {
const { columns, onSave } = this.props;
let params = new URLSearchParams();
columns.forEach((column, i) => {
if (column.field == 'source') {
params.append(column.field, 'CCP');
} else if (column.field == 'owner') {
params.append(column.field, this.props.username);
} else if (column.field !== undefined) {
params.append(column.field, this.refs[column.field].value);
}
}, this);
// You should call onSave function and give the new row
//onSave(newRow);
//api call
if (!isServiceName(params.get('name'))) {
//alert
console.log('Invalid name');
return;
}
if (!isServiceRef(params.get('ref'))) {
//alert
console.log('Invalid ref');
return;
}
params.append('quiet', 1);
let self = this;
this.props.addServices(params).then(function(response) {
let data = response.payload.data;
if (data.header.error) {
//@todo show error on input form
self.handleShowError(data.header.message);
} else {
let newRow = {};
newRow = data.body.recordset.record;
onSave(newRow);
self.sendDataBack(newRow);
}
});
};
initData() {
let self = this;
let promises = [];
promises.push(this.props.fetchExemptionType());
promises.push(this.props.fetchMarkets());
promises.push(this.props.fetchServiceDomains());
promises.push(this.props.fetchServicesList());
promises.push(this.props.fetchSecurityEngineerList());
promises.push(this.props.fetchBusinessPriorityList());
axios.all(promises).then(function(response) {
let data = response[0].payload.data;
self.exemptionType = data.body.recordset.record;
data = response[1].payload.data.body.recordset.record;
self.markets = Object.keys(data).map(key =>
data[key]
);
data = response[2].payload.data;
self.serviceDomain = data.body.recordset.record;
data = response[3].payload.data;
self.servicesList = data.body.recordset.record;
data = response[4].payload.data;
self.securityEngineerList = data.body.recordset.record;
data = response[5].payload.data;
self.businessPriority = data.body.recordset.record;
self.setState({ loaded: true });
});
}
updateCommsMatrix(service_id){
if(service_id > 0){
let self = this;
this.props.fetchCommsmatricesByService(service_id)
.then( response => {
let data = response.payload.data.body.recordset.record;
let options = self.populateOptionsObject(data, 'id', 'filename');
options.unshift({ value: '0', label: 'All'});
return options;
})
.then( options => this.setState({options:options,isLoading: false}));
}else{
this.setState({options:{ value: '0', label: 'All'},isLoading: false});
}
}
populateOptionsObject(options, key, value) {
return options.map((option, index) => (
{value : option[key], label: option[value] }
));
}
populateOptions(options, key, value) {
return options.map((option, index) => (
<option key={option.id} value={option[key]}>
{option[value]}
</option>
));
}
renderSelectField(field) {
let options = [];
if (field.label == 'Type') {
options = this.populateOptions(this.exemptionType, 'name', 'name');
} else if (field.label == 'Market') {
options = this.populateOptions(this.markets, 'name', 'name');
} else if (field.label == 'Service Domain') {
options = this.populateOptions(this.serviceDomain, 'name', 'name');
} else if (field.label == 'Service/Project/Programme') {
options = this.populateOptions(this.servicesList, 'id', 'name');
options.unshift(
<option key="0" value="0" selected>
All
</option>
);
} else if (field.label == 'Comms Matrix') {
options.unshift(
<option key="0" value="0" selected>
All
</option>
);
} else if (field.label == 'Security Engineer') {
options = this.populateOptions(this.securityEngineerList, 'email', 'email');
options.unshift(
<option key="0" value="" selected>
--Select Engineer--
</option>
);
} else if (field.label == 'Business Priority') {
options = this.populateOptions(this.businessPriority, 'name', 'name');
}
let id = "select_" + field.input.name;
return (
<div className="form-group">
<label className="control-label col-sm-2">{field.label}</label>
<div className="col-sm-10">
<select
id={id}
{...field.select}
name={field.input.name}
className="form-control form-control-inline"
type="select"
onChange={event => {
//props.input.onChange(event); // <-- Propagate the event
this.updateCommsMatrix(event.target.value);
}}
>
{options}
</select>
</div>
</div>
);
}
clearValue (e) {
this.select.setInputValue('');
}
updateValue (newValue) {
if(newValue !== null){
this.props.fetchExemptionsForCommsmatrix(newValue.value)
.then( response => {
if(this.state.toggleChecked){
this.checkedValues = response.payload.data.body.recordset.record.map((option, index) => (
{id : option['id'] }
));
}
this.setState({selectValue: newValue, policies : response.payload.data.body.recordset.record});
});
}else{
this.setState({selectValue: {value:"0",label:"All"}});
}
}
getCommsmatrices (input, callback) {
input = input.toLowerCase();
let options = this.state.options.filter(i => {
return i.label.toLowerCase().includes(input) == true;
//return i.label.toLowerCase().substr(0, input.length) === input;
});
let data = {
options: options,//.slice(0, MAX_CONTRIBUTORS),
complete: true //options.length <= MAX_CONTRIBUTORS,
};
setTimeout(function() {
callback(null, data);
}, ASYNC_DELAY);
}
gotoCommsmatrix (value, event) {
if(value.value > 0){
window.open(window.top.protocol + '://' + window.top.hostname + '/api/user/commsmatrix/id/'+value.value+'/format/xml');
}
}
/*
<Select
id={id}
//className="col-sm-6"
ref={(ref) => { this.select = ref; }}
onBlurResetsInput={false}
onSelectResetsInput={false}
autoFocus
options={options}
simpleValue
clearable={this.state.clearable}
name={field.input.name}
//disabled={this.state.disabled}
value={this.state.selectValue}
onChange={this.updateValue}
rtl={this.state.rtl}
searchable={this.state.searchable}
/>
*/
renderSelect2Field(field){
let id = "select_" + field.input.name;
return(
<div className="form-group">
<label className="control-label col-sm-2">{field.label}</label>
<div className="col-sm-4">
<Async
name={field.input.name}
multi={false}
value={this.state.selectValue}
onChange={this.updateValue}
valueKey="value"
labelKey="label"
loadOptions={this.getCommsmatrices}
onValueClick={this.gotoCommsmatrix}
cache={false}
isLoading={this.state.isLoading}
optionRenderer={(option) => {return option.label;}}
/>
</div>
</div>
);
}
renderTextField(field) {
let value = '';
if (field.label == 'Requestor') {
value = this.props.activeUser.email;
}
return (
<div className="form-group">
<label className="control-label col-sm-2">{field.label}</label>
<div className="col-sm-10">
<input
name={field.input.name}
className="form-control form-control-inline"
type="text"
{...field.text}
value={value}
/>
</div>
</div>
);
}
renderTextareaField(field) {
return (
<div className="form-group">
<label className="control-label col-sm-2">{field.label}</label>
<div className="col-sm-10">
<textarea
name={field.input.name}
className="form-control form-control-inline"
type="textarea"
{...field.text}
/>
</div>
</div>
);
}
handleCheckedValues({target}){
if (target.checked){
target.setAttribute('checked', true);
this.checkedValues.push({id:$(target).val()});
}else{
target.removeAttribute('checked');
let arr = this.checkedValues.filter(function(item) {
return item.id !== $(target).val()
})
this.checkedValues = arr;
}
}
actionButtons(cell, row, enumObject, rowIndex) {
let checked = true;
let arr = this.checkedValues.filter(function(item) {
return item.id == row.id
});
if(arr.length == 0){
checked = false;
}
return (
<input type="checkbox" defaultChecked={checked} name="comms_matrix_flow[]" value={row.id} onClick={this.handleCheckedValues} />
);
}
fnToggleCheckboxes({target}) {
this.setState({toggleChecked : !this.state.toggleChecked})
let elements = document.getElementsByName("comms_matrix_flow[]");
let length = elements.length;
if(!this.state.toggleChecked){
this.checkedValues = this.state.policies.map((option, index) => (
{id : option['id'] }
));
for(let i = 0;i<length;i++){
elements[i].checked = true;
}
}else{
this.checkedValues = [];
for(let i = 0;i<length;i++){
elements[i].checked = false;
}
}
}
renderPolicies(){
if(this.state.selectValue !== null && parseInt(this.state.selectValue.value) > 0){
return (
<div className="form-group">
<label className="control-label col-sm-2">Select Denied Flow(s):
<br/> <input name="toggle_comms_matrix_flow" type="checkbox" onClick={this.fnToggleCheckboxes} defaultChecked={true} />
Toggle All
<br/> <font style={{color: "#ff0000", fontSize: "11px"}}>
Only select and group flows relevant to the exemption request to
prevent it being declined. </font></label>
<div className="col-sm-10">
<BootstrapTable
keyField="id"
data={this.state.policies}
options={this.tableOptions}
pagination
striped
hover
tableHeaderClass="table-vf thead"
>
<TableHeaderColumn dataFormat={this.actionButtons.bind(this)} width={`30px`}></TableHeaderColumn>
<TableHeaderColumn dataField="src">Source</TableHeaderColumn>
<TableHeaderColumn dataField="dst">Destination</TableHeaderColumn>
<TableHeaderColumn dataField="protocol" >Protocol</TableHeaderColumn>
<TableHeaderColumn dataField="ports">Ports</TableHeaderColumn>
<TableHeaderColumn dataField="type" width={`60px`}>Type</TableHeaderColumn>
</BootstrapTable>
</div>
</div>
);
}
return (<div className="form-group"></div>);
}
render() {
console.log(this);
if (!this.runOnce && this.props.isReady) {
this.runOnce = true;
this.initData();
}
const { handleSubmit } = this.props;
let form = 'Loading...';
if (this.state.loaded) {
let policiesTable = this.renderPolicies();
return (
<div className="container-fluid">
<form onSubmit={handleSubmit} className="form-horizontal">
<Field
label="Type"
loadFrom="exemptionType"
name="exemption_type"
component={this.renderSelectField}
/>
<Field
label="Market"
loadFrom="markets"
name="market"
component={this.renderSelectField}
/>
<Field
label="Service Domain"
loadFrom="serviceDomain"
name="service_domain"
component={this.renderSelectField}
type="select"
/>
<Field
label="Service/Project/Programme"
loadFrom="servicesList"
name="service_id"
component={this.renderSelectField}
type="select"
/>
<Field
label="Demand Ref"
name="demand_ref"
component={this.renderTextField}
type="text"
/>
<Field
label="Exemption Summary"
name="name"
component={this.renderTextField}
type="text"
/>
<Field
label="Exemption Description"
name="description"
component={this.renderTextareaField}
type="textarea"
/>
<Field
label="Comms Matrix"
loadFrom="matrices"
name="comms_matrix_id"
component={this.renderSelect2Field}
type="select"
/>
{policiesTable}
<Field
label="Requestor"
name="requestor"
component={this.renderTextField}
type="text"
readonly="readonly"
/>
<Field
label="Security Engineer"
loadFrom="securityEngineerList"
name="security_engineer"
component={this.renderSelectField}
type="select"
/>
<Field
label="Link to Design Doc"
name="designdoc"
component={this.renderTextField}
type="text"
/>
<Field
label="Business Priority"
loadFrom="businessPriority"
name="business_priority"
component={this.renderSelectField}
type="select"
/>
<Field
label="Expiry date (dd-MMM-yy)"
name="expiry_date"
component={this.renderTextField}
type="text"
/>
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button id="btnSubmit" type="button" name="btnSubmit" className="btn btn-vodafone hidden-print">Submit</button>
</div>
</div>
</form>
</div>
);
}
return <div className="container-fluid">{form}</div>;
}
}
function mapStateToProps(state) {
return {
securityExemptions: state.securityExemptions,
commsmatrices: state.commsmatrices
};
}
//Anything returned from this function will end up as props
//on the User container
function mapDispatchToProps(dispatch) {
// Whenever getUser is called, the result should be passed
// to all our reducers
//return {
//actions: bindActionCreators(Object.assign({}, fetchServices, checkServiceEditable ), dispatch)
//};
return bindActionCreators(
{
fetchExemptionType,
fetchMarkets,
fetchServiceDomains,
fetchServicesList,
fetchCommsmatricesByService,
fetchExemptionsForCommsmatrix,
fetchSecurityEngineerList,
fetchBusinessPriorityList
},
dispatch
);
}
SecurityExemptionsNew = connect(mapStateToProps, mapDispatchToProps)(
SecurityExemptionsNew
);
//Decorate the form component
export default reduxForm({
form: 'SecurityExemptionsNewForm', // a unique name for this form
initialValues: { service_domain: 'Corporate (Internal/External)' }
})(SecurityExemptionsNew);
It seems to me when i select a value the input being passed into loadOptions
is blank so nothing gets display when selecting a value
in order to onChange work properly you must include two props and your onChange(selected, actionMeta)
ref: https://github.com/JedWatson/react-select/issues/2405#issuecomment-370526500
Hello -
In an effort to sustain the react-select
project going forward, we're closing old issues.
We understand this might be inconvenient but in the best interest of supporting the broader community we have to direct our efforts towards the current major version.
If you aren't using the latest version of react-select
please consider upgrading to see if it resolves any issues you're having.
However, if you feel this issue is still relevant and you'd like us to review it - please leave a comment and we'll do our best to get back to you!
Most helpful comment
@saadbinsaeed Doc just dont get updated yet. i will do this tommorow. u need to pass {value: '', label: ''} instead of string