I created a conditional field which displays yes and no radio buttons. If Yes is selected then the child components should be shown.
The following code accomplishes that. The issue is the selection of yes or no is not registered in the redux state. If I remove the onChange function then the redux state is updated with the Yes or No value, but of course the child components won't show.
I believe the onChange function I pass is overwriting some other onChange function passed by redux-form. Tried many things but had the same result.
I was thinking of just linking the value property with ReactLink, but it's deprecated.
Using React 0.15, Redux-Form 6.0 alpha, and ES7.
const YesNoRadioButtonGroup = (props) =>
<RadioButtonGroup {...props}>
<RadioButton value='Yes' label='Yes' className={s.radio}/>
<RadioButton value='No' label='No' className={s.radio}/>
</RadioButtonGroup>
// TODO: Clear child fields when "No" is selected
// TODO: See if we can generalize into ConditionalField
export class ConditionalRadio extends React.Component {
state = {conditional: false}
updateConditional(event) {
console.log(event)
this.setState({conditional: event.target.value === 'Yes'})
}
render() {
return <div>
<Field name={this.props.name}
component={YesNoRadioButtonGroup}
onChange={::this.updateConditional} /> // The trouble line.
{this.state.conditional ? this.props.children : null}
</div>
}
}
It is used like this:
<ConditionalRadio name='willRelocate'>
<Field name='willRelocateTo.withinCurrentState' component={Checkbox} label='Within Current State'/>
<Field name='willRelocateTo.outOfState' component={Checkbox} label='Out of State'/>
<Field name='willRelocateTo.outOfCountry' component={Checkbox} label='Out of Country'/>
</ConditionalRadio>
If you have defined the field name when creating your redux-form, then you just have to call the default onChange event for that field inside your custom change event handler.
In your case that should be:
updateConditional(event) {
this.setState({conditional: event.target.value === 'Yes'});
this.props.fields.name.onChange(event);
}
Did you try to use the function componentWillReceiveProps in which you can check the new value then set the new conditional? see all helpful React lifecycle functions here
Your Component would be written like this:
export class ConditionalRadio extends React.Component {
state = {conditional: false}
componentWillReceiveProps(nextProps) {
const displayChildren = nextProps.**value of the radio from redux form STORE** === 'Yes'
this.setState({conditional: displayChildren});
}
render() {
return (
<div>
<Field name={this.props.name}
component={YesNoRadioButtonGroup}/>
{this.state.conditional ? this.props.children : null}
</div>
)
}
}
This works well:
class YesNoRadioButtonGroup extends React.Component {
handleChange(event) {
// Call the event supplied by redux-form.
this.props.onChange(event)
// If custom handler exists, call it.
if (this.props.hasOwnProperty('customHandler')) {
this.props.customHandler(event)
}
}
render() {
return <RadioButtonGroup {...this.props} onChange={::this.handleChange}>
<RadioButton value='Yes' label='Yes' className={s.radio}/>
<RadioButton value='No' label='No' className={s.radio}/>
</RadioButtonGroup>
}
}
Related
I'm trying to connect material-ui ToggleButtonGroup with redux form and getting issues with this.
Here is my code:
<Field
name='operator'
component={FormToggleButtonGroup}
>
<ToggleButton value='equals'>Equal</ToggleButton>
<ToggleButton value='not_equals'>Not equal</ToggleButton>
</Field>
.. and my component, passed to Field:
const FormToggleButtonGroup = (props) => {
const {
input,
meta,
children
} = props;
return (
<ToggleButtonGroup
{...input}
touched={meta.touched.toString()}
>
{children}
</ToggleButtonGroup>
);
};
export default FormToggleButtonGroup;
the problem is, when I select value (toggle option), selected value is not passed to redux store, it passed only after loosing focus and then throws error 'newValue.splice is not a function'
Please help to deal with this issue
Sandbox with sample code
Playing with the component I finally found the solution.
I need manually assign new value got from ToggleButtonGroup component and put this value to redux store. Here is how working code looks:
const FormToggleButtonGroup = (props) => {
const {
input,
meta,
children,
...custom
} = props;
const { value, onChange } = input;
return (
<ToggleButtonGroup
{...custom}
value={value}
onChange={(_, newValue) => {
onChange(newValue);
}}
touched={meta.touched.toString()}
>
{children}
</ToggleButtonGroup>
);
};
Main change is getting redux's function onChange and call it with new value, selected when value toggled. There is onChange related to ToggleButtonGroup component and another onChange related to Redux. You need to call latter when ToggleButtonGroup's onChange occurs.
i have a parent component and i have called the child component in its HTML like this.
render() {
<EditBank
deal={dealDetailData && dealDetailData.id}
open={editBankModalStatus}
headerText={"Edit Bank Account"}
getInvestmentOfferingDetailsById = {() =>this.props.getInvestmentOfferingDetailsById({
id: this.props.match.params.id
})}
bankDetail={bankDetails}
toggleEditModal={() => this.handleEditModal("editBankModalStatus", {})}
/>
}
EditBank component is a modal which is only shown when editBankModalStatus is true and it is set to be true on a button click.
Now i want to set the state of EditBank only when button is clicked and whatever bankDetails has been passed to it.
I have tired componentDidMount lifecycle hook but it updated when component is rendered only.
I want to update the state of EditBank component when it is shown on screen only. Any help is appreciated.
Try do this :
render(){
return (
<div>
{editBankModalStatus === true &&
<EditBank
deal={dealDetailData && dealDetailData.id}
open={editBankModalStatus}
headerText={"Edit Bank Account"}
getInvestmentOfferingDetailsById = {() =>this.props.getInvestmentOfferingDetailsById({
id: this.props.match.params.id
})}
bankDetail={bankDetails}
toggleEditModal={() => this.handleEditModal("editBankModalStatus", {})}
/>
}
</div>
);
}
so EditBank will shown only if editBankModalStatus is true.
I'm creating a sample react application for learning purpose, in that I've following hierarchy of separate components:
<RadioButton>
//Radio buttons are rendered here and selection of radio buttons are maintained in state of this component
</RadioButton>
<SelectCard>
<RadioButton dataToPopulate = ['choice A', 'choice B'] />
</SelectCard>
<ParentSelectCard>
<SelectCard /> //Rendering SelectCard with passing some data as prop from here
</ParentSelectCard>
<Button /> //Custom button component
<HomeScreen>
<ParentSelectCard />
<Button />
</HomeScreen>
Now when I press the button, I want to navigate to other screen by passing the selected options in radio buttons.
I've read this article about lifting state up. But the problem is, here there is no common parent ancestor to which I can lift the state to.
If I list the state up to <HomeScreen> component, How can I manage the selections made in <RadioButton> component?
Here is the complete code of <RadioButton> component:
class RadioButton extends React.Component {
constructor(props) {
super(props);
this.state = {
radioSelected: 0
}
}
handleRadioClick(id) {
this.setState({
radioSelected: id
});
}
render(){
return this.props.dataToPopulate.map((element) => {
return (
<View key = {element.id} style={styles.radioButton}>
<TouchableOpacity style={styles.radioButtonTint} onPress = {this.handleRadioClick.bind(this, element.id)}>
{ element.id === this.state.radioSelected ? (<View style={styles.radioButtonSelected}/>) : (null) }
</TouchableOpacity>
<Text style={styles.radioButtonText}> {element.value} </Text>
</View>
);
});
}
}
Here you can see that the final choice made will be stored in the state of this component (in radioSelected).
What I'm missing here? Is my design of <RadioButton> wrong?
What I'm missing here? Is my design of is wrong?
Well if you "lift state up" the radio button itself should not have any state at all. Instead pass down a handler to the RadioButton:
<RadioButton onChange={value => this.doSomethingWith(value)} />
Then you can call that inside of the radio button whenevver something was changed, and handle the results in <App/>.
If you have to pass down that handler through multiple levels it might be better to use a context.
I developed a React App using Material-UI then I tried to create independent Components,
check the below independent components(<PanelDiv/>),
render() {
return (
<div className="panelDiv-component" style={{display:this.props.display}}>
<div className="panel-field-content">
<TextField
floatingLabelText={this.props.heading}
type={this.props.inputType}
value={this.props.value}
/>
{/* <input defaultValue className="form-control"></input>*/}
</div>
</div>
);
}
I tried to use the component like this,
<PanelDiv
heading='name'
inputType="text"
value={this.state.userData.name}
display={this.state.display[0]}
/>
But I can't update input field in this way.Also there is no error. How can i solve this? I want to update my input field.
Please check my input filed in the below image :
Because you are controlling the value of TextField by using value attribute but you are not updating the value by using onChange function, Since value of TextField is not changing so it becomes read only.
Solution:
Specify the onChange function with TextField and update the value inside that, Like this:
<TextField
floatingLabelText={this.props.heading}
type={this.props.inputType}
value={this.props.value}
onChange={this.props._change}
/>
Inside parent component:
_Change(event, value){
//update the value here
}
<PanelDiv
heading='name'
inputType="text"
value={this.state.userData.name}
_change={this._change}
display={this.state.display[0]}
/>
If you pass value as a prop to TextField you can't change that text!
On Material-UI official documentation they have used defaultValue="default val" as a prop.
So I used defaultValue as a prop! It worked fine for me!
<TextField
type="text"
defaultValue={this.props.val}
onChange={handleChange}
/>
Had the same error. I was not able to key in anything and it was because there was no name props included. example:
<TextField
type="email"
name='email'/>
Look at this example - https://jsfiddle.net/y857yeLq/
You should define a function, which is handles of text change and pass it to onChange property. In this example I used state for storing current text field value. I see, that you use props for that, but the principle is the same - function should update props in your case.
const { TextField, MuiThemeProvider, getMuiTheme } = MaterialUI;
class SliderExampleControlled extends React.Component {
state = {
value: '',
}
render() {
console.log(this.state);
return (
<div style={{width: '50%', margin: '0 auto'}}>
<TextField
hintText="Type here"
value={this.state.value}
onChange={(e) => this.setState(e.target.value)}
/>
</div>
);
}
}
const App = () => (
<MuiThemeProvider muiTheme={getMuiTheme()}>
<SliderExampleControlled />
</MuiThemeProvider>
);
ReactDOM.render(
<App />,
document.getElementById('container')
);
I was running into this problem as well and I needed the onClick function to take more than just the event I also needed it to take the row number because my state had an array representing the rows in a table. I was able to do that using this chunk of code
onChange={(e) => this.nameChange(e.target.value, row.row_num)}
then in my function called nameChange I was able to update the value
I am trying do do a simple implementation on a stateful component who's state is managed by a stateless Child. Currently the handler only triggers a console.log.
Expected behavior:
When an field is updated the parent component should trigger a console.log.
Actual behavior
The setInterest is never triggered and instead I'm getting an error about synthetic events:
This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property `nativeEvent` on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist().
The components render visually as expected, and I get no other errors either in the browser of Webpack.
Any help would be greatly appreciated.
Stateful component:
// Setting the parameters of the market
export class Parameters extends React.Component {
// Constructor setting default state
constructor ( props ) {
super ( props )
// Set the state objects
this.state = {
interest: {
pessimistic: this.props.pessimistic || 1,
historical: this.props.historical || 4,
optimistic: this.props.optimistic || 7
}
}
// Bind the functions for use in the render
this.setInterest = this.setState.bind( this )
}
// Set the parameters
setInterest( e ) {
console.log('I AM NEVER TRIGGERED')
}
// Rendering of message
render( ) {
return(
<div>
<ParametersView
handleChange={ this.setInterest }
interest={ this.state.interest } />
<DesiresView />
</div>
)
}
}
Stateless component
// Import react
import React from 'react'
export const ParametersView = ( { handleChange, interest } ) => {
return (
<div>
<span id="assumptions">
<input
onChange={ handleChange }
value={interest.pessimistic}
id="pessimistic" type="number" name="pessimistic" />
<input
onChange={ handleChange }
value={interest.historical}
id="historical" type="number" name="historical" />
<input
onChange={ handleChange }
value={interest.optimistic}
id="optimistic" type="number" name="optimistic" />
</span>
</div>
)
}
export const DesiresView = ( ) => {
return ( <p>No desire view yet</p> )
}
You have a typo.
this.setInterest = this.setState.bind( this ) needs to be
this.setInterest = this.setInterest.bind( this )