React-Bootstrap set value of FormControl Select - javascript

I have a FormControl which is a Select that I am using in a form. It works fine when adding a new resource, but when I want to edit an existing record I need to set the value of the control. I'm not seeing a good way to set the value of the select / combobox. This is what my JSX looks like.
<FormGroup controlId="group">
<ControlLabel>Group</ControlLabel>
<FormControl componentClass="select" placeholder="Group"
inputRef={ref => { this.groupSelect = ref; }}
onChange={this.groupSelect}>
<option></option>
{
this.state.groups.map(function (group) {
return <option key={group.id} value={group.id}>{group.name}</option>
})
}
</FormControl>
</FormGroup>
I've tried to access the component this way but it comes up undefined.
console.debug(this.groupSelect);
this.groupSelect.value(1);
UPDATE:
I'm trying the following, but this doesn't appear to be working either because I don't have access in the state, calling bind causes an error.
<FormGroup controlId="group">
<ControlLabel>Group</ControlLabel>
<FormControl componentClass="select" placeholder="Group"
inputRef={(ref) => { this.state.groupSelect = ref }}
onChange={this.groupSelect}>
<option></option>
{
this.state.groups.map(function (group) {
return <option key={group.id} value={group.id} selected={this.state.selectedGroupId == group.id}>{group.name}</option>
}).bind(this)
}
</FormControl>
</FormGroup>

You are missing a crucial piece here, which is you need to set the value of the component. Add:
value={this.state.groupSelectValue || defaultValue}
Where groupSelectValue is the value from the record you're editing, and the defaultValue is what you want to default to if there is no record or no value in the record.
Then, in the onChange event function (groupSelect(e)), you will do:
this.setState({
groupSelectValue: e.target.value
});
So that the state is updated with the selection.

The selected value should come from model (state or property), you are trying to achieve what you need with 'jquery way '- which is wrong.

Related

How can I store a selected value in react combobox

I created a combobox with react. How do I assign a value selected in the combobox to a variable or can I store it? Is there any example for this?
const PPP1 = props => {
return (
<div className='padding-div'>
<FormGroup controlId="exampleForm.SelectCustom" className='col-8'>
<FormLabel>1- Select Sector</FormLabel>
<FormControl as="select" custom>
<option> </option>
<option>Agriculture</option>
<option>Mining</option>
<option>Information</option>
<option>Finance</option>
<option>Real Estate</option>
<option>Other</option>
</FormControl>
</FormGroup>
</div>
)
}
export default PPP1
You might considering adding onChange props on FormControl component. Ie on this
const handleChange = (event) => {
setState({ ...state, [event.target.name]: event.target.checked });}
<FormControlLabel
control={<Checkbox checked={gilad} onChange={handleChange} name="gilad" />}
label="Gilad Gray"/>
If the FormControl object is rendered into a regular <select> tag, you could do the following:
Declare your state:
state = {
selectedData: '',
}
Then implement onChange function:
onChange = e => {
this.setState({ selectedData: e.target.value });
}
And then bind the function:
<FormControl as="select" custom onChange={ this.onChange} >
In the end, you could access the result, calling this.state.selectedData
Edit: I didn't notice that you use Function component, my solution is for a class component, but it could be easily translated. Please let me know if you need help doing that.

React "Maximum update depth exceeded."

I have a container which is a child container. This child container handles states and it also receives some props from the parent. I have two select statements which onChange sets state in the child container. For some reason, the setState() is causing the container to re render. The weird part is that the render() and also my setState() code is called only once. (I added debugger to check). Please find my Select combobox code below:
<Select
native
name="evidenceNode"
value={nodeType}
onChange={this.handleChange('nodeType')}
className={classes.textField}
>
<option />
{NODE_TYPE.map(function (item, i) {
return <option key={i} value={item}>{item}</option>
})}
</Select>
<Select
native
name="modelType"
value={modelType}
onChange={this.handleChange('modelType')}
className={classes.textField}
>
<option />
{MODEL_TYPE.map(function (item, i) {
return <option key={i} value={item}>{item}</option>
})}
</Select>
Here is my handleChange function:
handleChange = name => event => {
this.setState({
[name]: event.target.value,
});
};
I am suspecting that this is a very small fix but I don't know where am I going wrong.
Things I have tried:
Change the way I am calling handle change to a arrow function and it didnt work
I removed one of the Select statement and tried running again and it worked.
I tried to remove the handleChange call from one of the Select statement and it worked fine.
Also I should mention: I have a componentWillReceiveProps function (Not sure if it matters)
componentWillReceiveProps(nextProps, nextContext) {
if(nextProps.selectedNode !== this.state.selectedNode){
this.setState({
selectedNode: nextProps.selectedNode
});
}
}
The issue is onChange={this.handleChange('modelType')}.
You're not attaching an event, you're calling a method with that.
You're entering in an infinite loop because of that.
this.handleChange('modelType') occurs a re-render which call again this.handleChange('modelType')...etc
Attach on the onChange event an anonymous function which call handleChange
onChange={e => this.handleChange('modelType', e)}
And change handleChange params declaration :
handleChange = (name, event) => {}
The problem wasn't with the handleChange listener. Apparently [Material-UI]https://material-ui.com/ (The tool I am using for the form elements) required us to add a FormControl element above every Select I add. So the component should look something like this.
<FormControl
// className={classes.formControl}
>
<Select
native
name="nodeType"
value={nodeType}
onChange={this.handleChange('nodeType')}
className={classes.textField}
inputProps={{
name: 'nodeType',
id: 'nodeType'
}}
>
<option/>
{NODE_TYPE.map(function (item, i) {
return <option key={i} value={item}>{item}</option>
})}
</Select>
</FormControl>
The mistake I made was I had one FormControl and it had two Select elements inside it. This particular thing isn't documented properly on their website.
I think Material-UI recursively calls handleChange on every Select component inside the Form control and since I had more than one, it was going into a loop. I hope this helps.

How to add the input field inside the select option using ant design and react

I created select option using ant design .But I need create editable cell inside the select option.
This my select option code
<Select
showSearch
style={{ width: 400 }}
placeholder="Select a Bank"
optionFilterProp="children"
onChange={this.handleChange.bind(this)}
>
<option value="1">Bank1</option>
<option value="2"> Bank2</option>
<option value="3"> Bank3</option>
</Select>
And onChange functions is
handleChange(value) {
console.log(`selected ${value}`);
this.setState({
bank:value,
});
}
Can you help me?
I suppose the question is whether or not this is an editable list.
The Select component has a mode prop that can be used to change the functionality with the following options:
'default' | 'multiple' | 'tags' | 'combobox'
Using the tags mode would allow you to add and remove items and generate a tokenized list when the form is submitted.
If you are looking at a fixed list and then wanting to create new items to add to the list:
If you want to be able to add new items to the list, this doesn't exist currently, as far as I am aware.
You may be able to refashion something from the Ant Design Pro components, or otherwise come up with a solution where:
when "create" is selected, you toggle the Select for an Input
when the input is submitted/blurred update the Options list, toggle the Select/Input once more and submit the value to the back-end.
I hope this helps.
You don't need to do that actually. All you need to do is to use component state and two simple callback functions ant design provides for select.
So let's assume you need to allow users not to also search for existing values inside a Select but if it didn't exist they can choose a new one. So here's what I'd do:
Inside render() method:
<Select
showSearch
value={this.title}
filterOption={true}
onSearch={this.handleSearch}
onFocus={this.handleFocus}
style={{ width: "100%" }}>
{this.titles.map((title) => (
<Select.Option key={title}>{title}</Select.Option>
))}
</Select>
Where this.titles = ["something", "else"].
Then Inside this.handleSearchand this.handleFocus I'd write:
protected handleSearch = (value: string) => {
this.setState({ titles: value && value !== "" ? [...this.titles, value] : fileTitles });
};
protected handleFocus = () => {
this.setState({ this.titles });
};
What we're basically doing is to populate the options we're iterating over inside the Select with this.titles in the state of the component itself (don't confuse it with Redux or MobX) when user opens the selector and once user searches for anything that would be added to options as well. With this approach you won't need an input or a switch to show/hide inputs. Hope it helps.
You could use another modal to input the additional value.
Check this : https://codesandbox.io/s/antdselectaddoption-7fov7
Code from mamsoudi throws Errors, so i took his idea and made my own component that i'm sharing with you.
import React from 'react';
import {Select} from "antd";
class FieldSelectAndCustomText extends React.Component {
constructor(props) {
super(props);
this.initialTitles = ["something", "else"];
this.state = {
titles: this.initialTitles,
currentValue: null,
};
}
handleSearch = (value) => {
const titles = this.state.titles;
for (let i = 0; i < titles.length; i++) {
const isSearchValueInState = new RegExp(value).test(titles[i]);
if (!isSearchValueInState) {
this.setState({
titles: [...this.initialTitles, value],
currentValue: value
});
break;
}
}
};
handleChange = (value) => {
this.setState(prev => ({...prev, currentValue: value}));
}
render () {
return (
<div>
<Select
showSearch
value={this.state.currentValue}
filterOption={true}
onSearch={this.handleSearch}
onChange={this.handleChange}
onFocus={this.handleFocus}
style={{ width: "100%" }}>
{this.state.titles.map((title) => (
<Select.Option value={title} key={title}>{title}</Select.Option>
))}
</Select>
</div>
);
}
}

Unexpected behavior with material ui Select and 'redux-form'

I have a simple 'redux form' with a Select component from newest material-ui-next.
import { TextField } from 'material-ui';
<Field
name="name"
component={TextField}
select
>
<MenuItem value={1}>Lily</MenuItem>
<MenuItem value={2}>Mark</MenuItem>
</Field>
Works fine. Hovewer, if I change the value prop from typeof number to string, e.g.
<Field
name="name"
component={TextField}
select
>
<MenuItem value="lily">Lily</MenuItem>
<MenuItem value="mark">Mark</MenuItem>
</Field>
the value changes properly, but just after one second, the value becomes 0 (as it was initially), and the selected value disappears (it's empty from now on). It had a correct value just for a moment, but somehow it's being automatically set back to 0.
Even tried with rendering the field:
const renderSelectField = ({ input, label, meta: { touched, error }, children, ...custom }) => (
<TextField
{...input}
select
onChange={(event, index, value) => input.onChange(event.target.value)}
children={children}
{...custom}
/>
)
Still, it changes the value, and just after that it returns to 0. If I console.log the form values, it shows up (after manually changing the value):
{ name: "Lily" }
{ name: 0 }
{ name: 0 }
(it happens in period of one second)
Looking forward for any help. Thank you.
Edit: This is what happens in redux dev tools, when choosing an item with string value - in this case pln.
Based on this react-select issue and this redux-form issue it seems like you need to override the default onBlur event.

Specify default value to FormControl of react-bootstrap

In react-bootstrap#0.24.5 I've used Input attribute defaultValue to specify start value selected in combobox
<Input type='select'
ref='templateSelect'
defaultValue={this.state.templateId}
onChange={this.handleTemplateChange}>
{options}
</Input>
How this should be handled in react-bootstrap#0.30.7 ( newest one ) where Input was deprecated and new component that should be used here FormControl doesn't provide such attribute?
Should value be used instead?
<FormControl type='select'
ref='templateSelect'
value={this.state.templateId}
onChange={this.handleTemplateChange}>
{options}
</FormControl>
Or maybe something like this:
value={this.state.templateId || 'default value'}
I didn't test this, but from the React Bootstrap source code for FormControl it seems like using defaultValue prop should work:
<FormControl type="select"
ref="templateSelect"
defaultValue={this.state.templateId}
onChange={this.handleTemplateChange}>
{options}
</FormControl>
If multi select defaultValue must be array:
this.state = {
templateId:['some value']
}
<FormControl
multiple
type="select"
ref="templateSelect"
defaultValue={this.state.templateId}
onChange={this.handleTemplateChange}>
{options}
</FormControl>
With "react-bootstrap": "1.0.0-beta.14", the value prop is used:
<Form.Control as="select" value={user}>
{ users.map(opt => (<option>{ opt }</option>)) }
</Form.Control>
(Hi googlers!)
If you are attempting to load an array of options into the Form-Control (By a network-call, promise or other async function) make sure you dont render the Select-field until the options-array has been fully loaded. Or else the defaultValue wont work.
(True for react-bootstrap 1.0.0-beta.8. Your mileage may wary.)
This way you can set the default value.
<option >is any default</option>
{
dataoption.map(item => {
return <option key={item.Value} vlaue={item.Value} selected={defaultselect ? defaultselect == item.Value ? true : false : false} >{item.Text}</option>
})
}
</FormControl>
You may receive an error in the console:
Warning: Use the defaultValue or value props on instead of setting selected on .
But setting defaultValue or value does not solve your problem

Categories

Resources