Why can't I type in my fields? - reactjs

I am using redux-form and I cannot type inside of my inputs after I add the initialize method and componentDidUpdate(). When I try to type in my email no characters appear. I am guessing all the inputs become controlled? If so how would I handle that?
import { reduxForm, Field, initialize } from 'redux-form';
const CustomComponent = function(field) {
return(
<div>
<input { ...field.input } type={field.type} placeholder={field.placeholder} />
</div>
);
}
//class instantiation
componentDidUpdate(){
this.handleInitialize();
}
handleInitialize() {
const initData = {
"name": this.props.name
};
this.props.initialize(initData);
}
render() {
const { handleSubmit } = this.props;
return (
<div>
<form onSubmit={handleSubmit(this.onSubmit)}>
<div>
<Field name="name" component={CustomComponent} type="text" placeholder="Name" />
<Field name="email" component={CustomComponent} type="email" placeholder="Email" />
</div>
<button type="submit">Submit</button>
</form>
</div>
);
}

You can't define your CustomComponent inside the render() method. That will cause your component to lose focus when you first start typing into an input.
Have you set up the reducer properly in your Redux config?

Related

Setting the default value of an input field after data is retrieved causes the content to overlap and the "onChange" event not to be triggered

I have an "edit category" component in my React application.
The ID is passed through the URL.
When the component is mounted, the action "fetchCategory" is called, which updates the props on the component with the current category.
I have a form which I want to be pre-populated, which I'm currently doing using the defaultValue on the input.
However, this isn't reflected on the state and the label for the text field overlaps the input field.
Any help would be greatly appreciated. I'll leave snippets of my code below which could help with understanding what I'm trying to do.
import React, { Component } from "react";
import { connect } from "react-redux";
import { fetchCategory } from "../../store/actions/categoryActions";
class AddOrEditCategory extends Component {
componentDidMount() {
this.props.fetchCategory(this.props.match.params.id);
if (this.props.match.params.id) {
this.setState({
_id: this.props.match.params.id
});
}
}
handleSubmit = e => {
e.preventDefault();
console.log(this.state);
};
handleChange = e => {
this.setState({
[e.target.id]: e.target.value
});
};
render() {
const addingNew = this.props.match.params.id === undefined;
return (
<div className="container">
<h4>{addingNew ? "Add category" : "Edit category"}</h4>
<form onSubmit={this.handleSubmit}>
<div className="input-field">
<input
type="text"
id="name"
defaultValue={this.props.category.name}
onChange={this.handleChange}
/>
<label htmlFor="name">Category name</label>
</div>
<div className="input-field">
<input
type="text"
id="urlKey"
onChange={this.handleChange}
defaultValue={this.props.category.urlKey}
/>
<label htmlFor="urlKey">URL Key</label>
</div>
<button className="btn">{addingNew ? "Add" : "Save"}</button>
</form>
</div>
);
}
}
const mapStateToProps = state => {
return {
category: state.categoryReducer.category
};
};
export default connect(
mapStateToProps,
{ fetchCategory }
)(AddOrEditCategory);
EDIT: Included whole component as requested
You need to replace the 'defaultValue' attribute with 'value' in the inputs.
You are using a controlled vs uncontrolled component. You dont need to use defaultValue.
You can set the initial values on the promise success for fetchCategory
componentDidMount() {
this.props.fetchCategory(this.props.match.params.id).then(response => {
// Set the initial state here
}
}
OR in
componentWillReceiveProps(nextProps) {
// Compare current props with next props to see if there is a change
// in category data received from action fetchCategory and set the initial state
}
React docs
<form onSubmit={this.handleSubmit}>
<div className="input-field">
<input
type="text"
id="name"
onChange={this.handleChange}
value={this.state.name} //<---
/>
<label htmlFor="name">Category name</label>
</div>
<div className="input-field">
<input
type="text"
id="urlKey"
onChange={this.handleChange}
value={this.state.urlKey}
/>
<label htmlFor="urlKey">URL Key</label>
</div>
<button className="btn">{addingNew ? "Add" : "Save"}</button>
</form>

Copy one Redux Form Value to Another

function mapStateToProps(state) {
let returnObject = {};
if (state && state.form) {
if (
state.form.someFormName &&
state.form.someFormName.values &&
state.form.someFormName.values.fieldNameX &&
state.form.someFormName.values.fieldNameX === "1"
) {
state.form.someFormName.values.fieldNameB =
state.form.someFormName.values.fieldNameA;
state.form.someFormName.values.fieldNameC =
state.form.someFormName.values.fieldNameD;
state.form.someFormName.values.fieldNameF =
state.form.someFormName.values.fieldNameE;
}
}
return returnObject;
}
This is Working Fine on selecting form field i am just copying redux form value to another field,How to do in Efficient Way?This is the Correct way to copy one form field into another ?
You can use formValueSelector to connect to your form value and than dispatch change action creator to update any field with your value.
Here is the example with textboxes(you can update it to use datePicker):
import {change, formValueSelector} from 'redux-form';
let FormName = (props) => {
const {dispatch, handleSubmit, firstValue} = props;
return <form onSubmit={handleSubmit}>
<div>
<label>First Value</label>
<Field
name='firstValue'
component='input'
type='text'
placeholder='First Value'
/>
</div>
<div>
<label>Copy value</label>
<div>
<Field
name='checkbox'
component='input'
type='checkbox'
value='checkboxValue'
onChange={(e) => {
if (e.target.checked) {
dispatch(change('formName', 'secondValue', firstValue));
}
}}
/>
</div>
</div>
<div>
<label>Second Value</label>
<Field name='secondValue' component='input' type='text'/>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
};
const selector = formValueSelector('formName');
connect(
state => ({
firstValue: selector(state, 'firstValue'),
})
)(FormName);
This is not the Preferred method to change the state like this (You are mutating the state) Redux 2 Principle,Use this instead:
If you are using radio/checkbox, then onPress of that radio/checkbox you can copy all the field,then dispatch onChange action.
For Eg:
<Field
type="radio"
name="fieldNameX"
value="1"
onRadioPress={this.someMethod}
component={CustomRadioButton}
/>
someMethod() {
let formValues = Object.assign({}, this.props.formValues);
this.props.dispatch(
change("SomeForm", "fieldWantToCopy", value)
);
}

how to provide validations for react js form

How to provide validations for react js form.
I have taken form with two fields. if two fields are enabled then only need to enable save button.
import React from 'react'
import { Button, Checkbox, Form } from 'semantic-ui-react'
const FormExampleForm = () => (
<Form>
<Form.Field>
<label>First Name</label>
<input placeholder='First Name' />
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input placeholder='Last Name' />
</Form.Field>
<Form.Field>
<Checkbox label='I agree to the Terms and Conditions' />
</Form.Field>
<Button type='submit'>Submit</Button>
</Form>
)
export default FormExampleForm
In redux forms 6.7 there's a simple property called pristine which can be used to do this. But if the user enters some value in at least one input field the submit button gets activated. To achieve that you may need to do something like this.
render() {
// const { handleSubmit } = this.props;
const {handleSubmit, pristine, reset, submitting} = this.props
return (
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<div>
<label>First Name</label>
<div>
<Field name="firstName" component="input" type="text" placeholder="First Name"/>
</div>
</div>
<button type="submit" className="btn btn-primary" disabled={pristine || submitting}>Submit</button>
</form>
);
}
}
But if you need to enable submit button, say when the user inputs values in 2 given fields or so, then this becomes complex. You need to do something like this. Here's my sample usecase. The form has 3 fields firstName, lastName and age. The submit button gets activated only if the user enters values for firstName and lastName input fields here. Please check out the following code.
import React, { Component } from 'react';
import { Field, reduxForm, formValueSelector } from 'redux-form';
import { connect } from 'react-redux';
class UserNew extends Component {
constructor(props) {
super(props);
this.isSubmitEnabled = this.isSubmitEnabled.bind(this);
}
onSubmit(values) {
console.log(values);
}
isSubmitEnabled() {
// Access field values here and validate them
const firstName = this.props.firstNameValue;
const lastName = this.props.lastNameValue;
if(firstName && lastName){
return true;
}
return false;
}
render() {
const { handleSubmit } = this.props;
const isEnabled = this.isSubmitEnabled();
return (
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<div>
<label>First Name</label>
<div>
<Field name="firstName" component="input" type="text" />
</div>
</div>
<div>
<label>Last Name</label>
<div>
<Field name="lastName" component="input" type="text" />
</div>
</div>
<div>
<label>Age</label>
<div>
<Field name="age" component="input" type="text" />
</div>
</div>
<button type="submit" className="btn btn-primary" disabled={!isEnabled}>Submit</button>
</form>
);
}
}
UserNew = reduxForm({
form: 'UserNewForm'
})(
UserNew
);
// Decorate with connect to read form values
const selector = formValueSelector('UserNewForm') // <-- same as form name
UserNew = connect(state => {
const firstNameValue = selector(state, 'firstName')
const lastNameValue = selector(state, 'lastName')
return {
firstNameValue,
lastNameValue,
}
})(UserNew)
export default UserNew;
To access field values you need to use formValueSelector in ReduxForms. For that you need to connect your form to redux store using connect helper.
Hope this helps. Happy coding !
Either you can use Redux-form as its not used in above code, so you can write custom JS validation code. For this you need to follow below
Initialise state in
contructor(){
this.state{
first_name: null,
last_name: null,
}
}
Change state of every input element onChange onChange={()=>this.setState({first_name: event.target.value})}
Now add onClick property to <Button onClick={this.handleSubmit} />
inside handleSubmit() you can get values through local state of component and add validation rules like
if(this.state.first_name =="") {
console.log("Enter first name")
}

Redux-form onSubmit nothing happens

I would like to ask, what I miss on my code. It seems submitForm function is not working/triggering when I submit the form. I can't get values from my form fields. Here's my code:
import React from 'react';
import { reduxForm,reset, Field } from 'redux-form';
class FormProfile extends React.Component {
submitForm(formProps){
console.log(formProps);
}
render(){
const { error, handleSubmit } = this.props;
return (
<form onSubmit={this.submitForm.bind(this)}>
<Row>
<Col lg={6}>
<Field name="name" type="text" component={TextBoxComponent} placeholder="Compay Name" label="* Company Name" required />
<Field name="website" type="text" component={TextBoxComponent} placeholder="www.yourdomain.com" label="Website" />
<Field name="email" type="text" component={TextBoxComponent} placeholder="How can we contact your Company" label="* Contact Email" required />
</Col>
</Row>
</form>
);
}
}
const form = reduxForm({
form: 'CreateCompanyProfileForm',
validate
});
function validate(formProps){
const error = {};
return error;
}
export default (form(FormProfile));
TextBox Componen
import React from "react";
class TextBoxComponent extends React.Component {
render(){
return (
<div className="form-group">
<label className="control-label">{this.props.label}</label>
{ this.props.sublabel !== undefined ?
<em className="text-info"> { this.props.sublabel }</em>
:null}
<input { ...this.props } type={this.props.type} placeholder={this.props.placeholder} className="form-control"/>
{ this.props.required && <span className="text-error"></span> }
</div>
);
}
}
export default TextBoxComponent;
You should modify this line:
<form onSubmit={this.submitForm.bind(this)}>
to:
<form onSubmit={handleSubmit}>
then you can remove:
submitForm(formProps){
console.log(formProps);
}
Then you can create a new component to wrap redux form component:
class SamplePage extends React.Component {
handleSubmit = (values) => {
// Do something with the form values
console.log(values);
}
render() {
return (
<FormProfile onSubmit={this.handleSubmit} />
);
}
}
Anyway, you should check the example from Redux-form docs: http://redux-form.com/6.5.0/docs/GettingStarted.md/

redux-form - onSubmit doesnt work

I'm using redux-form and I just cant get the onSubmit fuction to work.
EDIT: My problem is that the function is not being called, i put debugger on the onSubmit and it doesnt get there.
here is my form:
class userForm extends Component {
onSubmit(values) { // do here something }
render() {
const { handleSubmit } = this.props;
return <form onSubmit={handleSubmit(this.onSubmit)}>
<Field name='id'
component={TextField}
label='id'/>
<Field name='name'
component={TextField}
label='name' />
<button type='submit'>Submit</button>
</form>
}
}
export default reduxForm({
form: 'userForm'
})(userForm);
But it never gets to the onSubmit method.
What am I doing wrong?
you just need to add .bind keyword after submit,
class userForm extends Component {
onSubmit(values) { // do here something }
render() {
const { handleSubmit } = this.props;
return <form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<Field name='id'
component={TextField}
label='id'/>
<Field name='name'
component={TextField}
label='name' />
<button type='submit'>Submit</button>
</form>
}
}
export default reduxForm({
form: 'userForm'
})(userForm);
This is an edited version of the pattern I use.
Note the use of the bind keyword.
Generally I use redux to manage state, and would also use an action inside the function handleFormSubmit. But this should get you on the right track.
import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
class Userform extends Component {
static handleFormSubmit({ id, name}) {
console.log({id, name});
}
render () {
const { handleSubmit, fields: { id, name }} = this.props;
return(
<form onSubmit={handleSubmit(Userform.handleFormSubmit.bind(this))}>
<fieldset>
<label>Id:</label>
<input {...id}/>
</fieldset>
<fieldset>
<label>Name:</label>
<input {...name} />
</fieldset>
<button action="submit">Submit</button>
</form>
);
}
}
export default reduxForm({
form: 'userform',
fields: ['id', 'name']
})(Userform);

Resources