React-Redux-Forms enable checkbox in another react component - reactjs

I have given someone else's React project which is using the React-Redux-Form (this is not the redux-form) and there is a need to enable a checkbox which is on another React Component based upon a value being entered in a textbox in the React-Redux-Form. By defult the checkbox is disabled and should only be enabled if a value is present.
Searching on the Internet have failed to find an example in which to use. Can anyone help?

Here is a very rough example, and is not intended to run - simply show the flow of how to do it:
The component with the input field might have something like:
//1) this is setting a local state, when the user submits you can send it to redux so that it is available across the app.
this._saveInputToLocal() {
var emailRegEx = /^.+#.+\..+$/i;
this.setState({
email: e.target.value
}, function() {
}.bind(this));
},
//2) when the user clicks submit - send the input to redux
//lets assume this is saved into a property on state called `formInput`:
this._saveInputToRedux() {
const = { dispatch }
dispatch(saveUserInput(this.state.email))
},
render: function(){
return (
<div className={`field email ${css(styles.emailContainer)}`}>
<input
type='email'
placeholder={ 'helloworld#code.com' }
onChange={this._saveEmailToState}
/>
</div>
<button type='submit' onClick={this._saveInputToRedux}>Submit</button>
)
}
});
So you see, you have a few things: a function that updates a local state, and one that handles the submit - where the value of the local state fires and action that will store that value in redux. Don't forget to import connect so that you have dispatch available to you on props, and also don't forget to import your action into the component.
Now, In the other component that has the checkbox:
// 3) assuming you have mapped your redux state to your props you make a function that checks for a valid input value:
this._hasValidValue() {
const { formInput } = this.props
return formInput && formInput !== null && formInput !== undefined && formInput.length > 0
}
//here in the render you display either an enabled or disabled checkbox based on if you have a valid input from the other component. Because this is based on state, this component will re-render when state is updated (goes from invalid to valid or vice versa)
render: function(){
return (
<div className="checkbox">
{ hasValidValue()
? <input type="checkbox" name="some-name" />
: <input type="checkbox" name="some-name" disabled/>
}
)
}
});

Related

react-final-form input.onChange(null) does not update state immediately

We currently have a component <RenderDropdown /> which renders a material-ui <Select /> element. This takes options as props and is wrapped in a react-final-form <Field />.
Our issue is when we load the initialValues props of the <Form />, there are a few cases where the selected dropdown value no longer exists in the dropdown, so we want to set the dropdown value to null. We do that within the <RenderDropdown />:
componentDidMount() {
this.clearInputIfValueDoesntExistInOptions();
}
componentDidUpdate() {
this.clearInputIfValueDoesntExistInOptions();
}
clearInputIfValueDoesntExistInOptions() {
const {
input: { value, onChange },
options
} = this.props;
// Clear input value if it doen't exist in options
if (
value &&
!options.some((option) => option.key === value || option.value === value)
) {
console.log(
"clearInputIfValueDoesntExistInOptions",
"Setting value to null as the selected value does not exist in the current dropdown's options"
);
// If I use input.onChange, it does not update the final form state to null immediately.
onChange(null);
}
}
This does set the value to null, but the form state does not update immediately, so the UI does not update either. It only updates once we change another field value or if we submit the form.
I've made a quick demo that simulates our issue:
https://codesandbox.io/s/react-final-form-inputonchange-null-k7poj
Thanks.

Enzyme change another input field

I have a simple React component which has one email input field and a checkbox like this:
interface MyProps {
onSubmit?: (form: any) => void;
}
class Preferences extends React.Component<MyProps> {
state = {
primaryEmailCheckbox: false,
primaryEmail: "",
};
onPrimaryEmailChange = e => {
this.setState({ primaryEmail: e.target.value });
let checkbox = document.getElementById("primaryEmailCheckId") as HTMLInputElement;
checkbox.disabled = false; //<<< checkbox is null. lets say this is line 18
}
}
render() {
return (
<StaticContent />
<h3>Email Address</h3>
<div className="ui mini icon input">
<input type="email" value={this.state.primaryEmail} placeholder="Enter email..." onChange={this.onPrimaryEmailChange} />
</div>
<div className="ui checkbox">
<input type="checkbox" disabled={true} id="primaryEmailCheckId" onChange={e => this.setState({ primaryEmailCheckbox: e.target.checked })} /><label> Continue to receive further email communications from Us </label>
</div>
);
}
}
export default Preferences;
When anyone enters any thing on the email field, the checkbox becomes visible for user to check it or keep it unchecked.
When I run the application, it works as expected. But when I test it, it says checkbox is null (at line 18), so you cannot set disabled on that.
This is a test to test Preferences Component:
import * as React from "react";
import { shallow } from "enzyme";
import Preferences from "../../components/Preferences";
test("Preferences shows email and checkbox", () => {
const wrapper = shallow(<Preferences onSubmit={() => { }} />);
wrapper.find("input").at(0).simulate("change", {
target: {
value: "a#b.c",
}
});
expect(wrapper.find("input").state().value).toEqual("a#b.c");
});
This throws Null exception at line 18. The thing is, the value a#b.c is passed correctly and I verified it by placing log statements.
But, when I try to change the value of input type email, it calls a onChange method which tries to access (and change) the value of another input field.
I don't know how to change the value of 2nd input type which is a checkbox. How I can I make it work? Any help is appreciated.
This is because the shallow(...) rendering method provides a limited set of interaction patterns and document.getElementById(...) is not one of them. You should be able to get what you want using the following:
const wrapper = mount(<Preferences />, { attachTo: document.body });
(Docs for the above code. You can swap out document.body for the relevant equivalent if you're using something like JSDOM or similar).
That said... using document.getElementById at all is a huge red-flag in React development. Because React lets you interact with a virtual DOM and handles the application of that to the real DOM, fiddling with the real one yourself is a great way to end up with all sorts of bugs. A much better option would be to use refs to access the checkbox in the "React way", or just make checkboxEnabled: boolean part of your state and update it inside your onPrimaryEmailChange() method.

how to use semantic UI React Checkbox toggle?

I am trying to use Semantic UI react for layout. These are the following sample code I am having trouble with onChange. I can check to click the toggle but resets everytime I refresh.
import {
Checkbox
} from 'semantic-ui-react'
onChangeInput(event) {
let name = event.target.name
let value = event.target.value
let talent = this.state.newTalentProfile
talent[name] = value
this.setState({
newTalentProfile: talent
})
}
<Select
name = "willing_to_relocate"
ref = "willing_to_relocate"
defaultValue = {this.props.talent.willing_to_relocate}
onChange = { this.onChangeInput.bind(this)} >
<Option value = ""label = "" / >
<Option value = "YES"label = "YES" / >
<Option value = "NO"label = "NO" / >
</Select>
the below code doesn't work, but the above one works when i make changes it saves it to database
<Checkbox toggle
name = "willing"
ref = "willing"
label = "Willin To Relocate"
onChange = {this.onChangeInput.bind(this)
}
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
onChangeCheckbox = (evt, data) => {
let checked = data.checked
console.log(checked)
}
<Checkbox toggle label='Running discounted price?'
onClick={(evt, data)=>this.onChangeCheckbox(evt, data)}
/>
This should do the trick.
Your code suggests you expect event.target to be a checkbox element, but it is not. If you examine the variable event.target within your browser, you'll notice that it points to a label element, not the checkbox itself. Therefore, I'm guessing that your event.target.value and event.target.label are evaluating to null, causing the rest of your code to not function the way you expect.
There's many ways to get around this. One way is to set a state variable for your component to represent the state of the checkbox:
class TheComponentThatContainsMyCheckbox extends Component {
state = {
textValue: null,
willingToRelocate: true
}
...
Then, you can create a handler that toggles this state when checked:
toggleCheckBox = () => {
const willingToRelocate = !(this.state.willingToRelocate);
this.setState({willingToRelocate});
// Note: if you have other logic here that depends on your newly updated state, you should add in a callback function to setState, since setState is asynchronous
}
Notice that I'm using arrow syntax here, which will automatically bind this for me. Then, hook it up to the onChange event of the Semantic UI Checkbox:
<Checkbox label='Willing to Relocate.' onChange={this.toggleCheckBox}/>
You can now use your this.willingToRelocate state to decide other application logic, passing it up or down using whatever state management pattern you like (state container/store like Redux, React Context, etc.).
I assume your this.onChangeInput handles database updates.
semantic ui react offers a prop checked for Checkbox.
You should have a state {checked: false} in your code, then this.setState whatever in componentDidMount after retrieving the database record.
Pass this.state.checked into checked prop of Checkbox.

How to stop typing at certain length in Redux form text field?

I want a validation for my add credit card form, in which I want that the user should be unable to type in after 16 character in text field. What is the best way to do something like this.
<Input
value={this.state.cardNo}
onChange={event => {
if (event.target.value && event.target.value.length <= 16) {
this.setState({ cardNo: event.target.value });
}
}}
/>;
Use state and check length is <= 16 then only setState else leave and put state value in input value and while submitting value u can submit from state.
Note: You don't need to use redux just for client side validation.
In case of redux forms:
use this reference
import { actions } from 'react-redux-form';
function emailIsValid(email) {
// terrible validation, I know
return email && email.length > 0;
}
// in the connected component's render() method...
const { dispatch, user } = this.props;
return
<input type="text"
onChange={(e) => e.target.value.length <= 16 && dispatch(actions.change('user.email', e))}
/>
My suggestion is not to use redux forms that will gives a lot performance issues

How to reset initial value in redux form

I'm using redux-form. I'm showing initial values in input fields from the state.
When I click on reset, the input field is still showing initial values.
How can I reset the input field?
This is my code :
const mapStateToProps = (state) => {
return {
initialValues: {
name:state.userInfo.data.name,
email:state.userInfo.data.email,
phone:state.userInfo.data.phone,
city:state.userInfo.data.city.name,
}
};
}
This is how I'm calling initial value in the input field.
const renderField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<input className="form-control control_new" {...input} placeholder={label} type={type}/>
{touched && ((error && <span>{error}</span>))}
</div>
)
<Field type="text" {...name} name="name" component={renderField} label="Enter Your Name" />
Thanks
import {reset} from 'redux-form';
...
dispatch(reset('myForm')); // requires form name
Harsha's answer is correct, but you can also call this.props.reset(), which already knows your form name, from inside your decorated form component.
You can see it in action on the "Clear Values" button in the Simple Example.
TLDR: set enableReinitialize: true on your form
I had this same problem recently and came across this post, with none of the answers working. Finally found the solution so hopefully this will help someone else. the problem is those initial values not getting reset when you reset the form. here is a github issue asking about it, and here is the current documentation about it
Upon onClick of the clear button call a different function as follows.
onClick={this.onClearChanges}
Pass the initialValues to the function this way, and as everyone mentioned, Don't forget to set enableReinitialize: true.
onClearChanges = () => {
const { reset, onClearChanges, InitialValues } = this.props;
reset();
onClearChanges(InitialValues);
};
It's also possible to reset inside of your constructor if you don't have a button with a method to call.
I'm using a Drawer Navigator to navigate to different screens(not a clickable button with an onClick method) so I had to reset
constructor(props) {
super(props);
this.props.reset(); //<-- this
}
inside of the first component to handle that specific redux form and then I set
enableReinitialize: true
for that form.

Resources