Using react-datepicker alongside redux-form? - reactjs

I'm trying to use redux-form along with react-datepicker but keep getting the following error:
Warning: Failed prop type: Invalid prop `value` of type `object` supplied to `DatePicker`, expected `string`.
I have my code setup as follows:
renderDatePicker({input, placeholder, defaultValue="01/01/2018", meta: {touched, error} }) {
return (
<div>
<DatePicker {...input} dateForm="MM/DD/YYYY" selected={input.value ? moment(input.value) : null} />
{touched && error && <span>{error}</span>}
</div>
)
};
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.submit.bind(this))}>
<Field name='budgetDateDue' component={this.renderDatePicker} format={(value, name) => value || null} />
<button type='submit'>Submit</button>
</form>
)
}
I can't seem to get around this Warning and I haven't found much online aside from what I have already done.

input is an object, and input.value is a moment object. <DatePicker /> is expecting a string, so you'll need to pass it one. Convert the moment object to a string (and format it however you want).
<DatePicker
{...input}
value = {moment(input.value).format('MM-YYYY')}
dateForm = "MM/DD/YYYY"
selected = {input.value ? moment(input.value) : null}
/>

You can create a custom datepicker and pass props to it
const datePicker = ({ input, label, type, className, selected, meta: { touched, error } }) => (
<div>
<div>
<DatePicker {...input}
selected={selected}
placeholder={label}
type={type}
className={className}
dropdownMode="select"
/>
{touched && error && <span className="error_field">{error}</span>}
</div>
</div>
)
And in redux-form component you can do something like this
<Field
name="date_of_birth"
component={datePicker}
type="text"
selected={this.state.date_of_birth}
onChange={this.handleChange.bind(this)}
className="form-control"
/>

Any of the samples below worked for me, this was my solution:
class DateField extends Component {
render() {
const {
input,
meta: { error, touched },
} = this.props;
return (
<div>
<DatePicker
{...input}
dateForm="MM/DD/YYYY"
selected={input.value && input.value}
onChange={time => {
input.value = time ? time : null;
}}
onBlur={() => input.onBlur(input.value)}
/>
{touched && error && <span className="error-block">{error}
</span>}
</div>
);
}
}
export default DateField;
Then wrap this in a Form element.

Related

Ref with custom class - reactdate picker

I am trying to set focus on react datepicker when enter is pressed on earlier component(input filed).
I read a official documentation, and example with simple field is worked, but when I change with DatePicker I get a old error
TypeError: this.inputAccountDate.focus is not a function
My function is:
function CustomDatePicker(props) {
return (
<div>
{/* <input ref={props.innerRef} /> */}
<DatePicker className="form-control"
placeholderText="Izaberite datum"
dateFormat="dd/MM/yyyy"
maxDate={new Date()}
ref={props.innerRef}
/>
</div>
);
}
And snippet code from class with form is:
<Col className="pr-md-1" md="3">
<FormGroup >
<label>Datum računa</label>
<div>
<CustomDatePicker
innerRef={(input) => { this.inputAccountDate = input }}
/>
</div>
</FormGroup>
</Col>
Component where I call a function to set focus is
<Col className="pr-md-1" md="3">
<FormGroup>
<label>Broj računa</label>
<Input style={{'borderColor':'lightgray', 'fontSize':'14px'}}
innerRef={(input) => { this.inputAccountNumber = input }}
onKeyDown={this.focusAccountDate}
placeholder="Br.računa"
type="text"
value={this.state.accountNumber || (header === null ? "" :
header.account_number) }
onChange={this.changeAccountNumber}
onFocus={(e)=>e.target.select()}
required
/>
</FormGroup>
</Col>
Function which managing a focus is
focusAccountDate = (e) => {
if(e !== undefined) {
if(e.key === 'Enter') {
this.inputAccountDate.focus()
}
}
}
and inputAccountDate is this.inputAccountDate = React.createRef()
Use setFocus() instead of focus. There is no focus in DatePicker
In functional Component, the passing ref reference with props is not a valid way.
You need to know Forwarding Ref
Your CustomDatePicker should be changed like the following.
function CustomDatePicker(props, ref) {
return (
<div>
<DatePicker className="form-control"
placeholderText="Izaberite datum"
dateFormat="dd/MM/yyyy"
maxDate={new Date()}
ref={ref}
/>
</div>
);
}
export default React.forwardRef(CustomDatePicker)

How to set state for text box in functional component

I am working on React JS. I have one text-box component and I want to show some default value in it. After that, the user should be allowed to change the value. Now I am unable to change the value. The text box is behaving like read-only. Below is my code
const EditStyleFormComponent = ({
submitting,
invalid,
}) => (
<form className={className} onSubmit={handleSubmit}>
<h2>LSPL (Low Stock Presentation Level)</h2>
<Line />
<InputGroup>
<TextFieldWithValidation name="lsplMan" label="LSPL Manual" input={{ onChnage:'', value: 'Current' }} />
</InputGroup>
</form>
);
Below is my TextFieldWithValidation code.
export const TextFieldWithValidationComponent = ({
meta,
input,
noStyles,
...otherProps
}) => (
<TextField
state={noStyles ? textFieldStates.DEFAULT : getState(meta)}
errorMessage={meta.touched ? meta.error : null}
{...input}
{...otherProps}
/>
);
Below is my TextField code.
const TextField = ({
className,
label,
description,
state,
errorMessage,
isEditable,
spaceAtBottom, // Not used, but we don't want it in otherProps
...otherProps
}) => {
const inputId = _.uniqueId();
return (
<div className={className}>
{label &&
<label htmlFor={inputId}>{label}</label>
}
<div className="input-group" id={isEditable ? 'editable' : 'readonly'}>
<input
id={inputId}
readOnly={!isEditable}
{...otherProps}
/>
{getStatusIcon(state)}
{errorMessage &&
<Error>{errorMessage}</Error>
}
{description &&
<Description>{description}</Description>
}
</div>
</div>
);
};
Can someone help me to fix this issue? Any help would be appreciated. Thanks
You can use State Hook for manage state in functional component.
Example :
const Message = () => {
const [message, setMessage] = useState( '' );
return (
<div>
<input
type="text"
value={message}
placeholder="Enter a message"
onChange={e => setMessage(e.target.value)}
/>
<p>
<strong>{message}</strong>
</p>
</div>
);
};
Yu defined onChange as empty string in EditStyleFormComponent component. So on any change input component just do nothing.
onChange should be some function that will update value.
If you want to use functional components there are two possible solutions:
Lift state up to parent component of EditStyleFormComponent (in case parent is class based component)
Use React Hooks like so (just example!)
const EditStyleFormComponent = ({
submitting,
invalid,
}) => {
const [inputValue, setInputValue] = useState ('Current'); // default value goes here
return <form className={className} onSubmit={handleSubmit}>
<h2>LSPL (Low Stock Presentation Level)</h2>
<Line />
<InputGroup>
<TextFieldWithValidation name="lsplMan" label="LSPL Manual" input={{ onChnage: (e) => { setInputValue(e.target.value); }, value: inputValue }} />
</InputGroup>
</form>
};

Programatically changing a FieldArray value in Redux-Form

I'm trying to figure out how to use this.props.dispatch(change) in order use one field selector value to update another fields value within a FieldArray.
https://codesandbox.io/s/2p7k7jn930
I can't seem to get the syntax in this correct.
this.props.dispatch(
change("FieldArraysForm", `${props.member}.firstName`, this.props.hasLastName)
);
Any thoughts? Expected behavior would be to add a member and then have anything typed into the Last Name field be programmatically updated in the First Name field.
/**
The following can replace the file in the Field Arrays example
(https://github.com/erikras/redux-form/tree/master/examples/fieldArrays) to demonstrate this functionality.
**/
import React from "react";
import { connect } from "react-redux";
import {
Field,
FieldArray,
reduxForm,
formValueSelector,
change
} from "redux-form";
import validate from "./validate";
const selector = formValueSelector("fieldArrays");
const renderField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<label>{label}</label>
<div>
<input {...input} type={type} placeholder={label} />
{touched && error && <span>{error}</span>}
</div>
</div>
);
class Member extends React.Component {
componentDidUpdate(prevProps, props) {
if (this.props.hasLastName !== prevProps.hasLastName) {
this.props.dispatch(
change("FieldArraysForm", `${props.member}.firstName`, this.props.hasLastName)
);
}
}
render() {
const { member, index, fields, hasLastName } = this.props;
return (
<li key={index}>
<button
type="button"
title="Remove Member"
onClick={() => fields.remove(index)}
/>
<h4>Member #{index + 1}</h4>
<Field
name={`${member}.firstName`}
type="text"
component={renderField}
label="First Name"
/>
<Field
name={`${member}.lastName`}
type="text"
component={renderField}
label="Last Name"
/>
{hasLastName && <p>{hasLastName}</p>}
</li>
);
}
}
Member = connect((state, props) => ({
hasLastName: selector(state, `${props.member}.lastName`)
}))(Member);
const renderMembers = ({ fields, meta: { touched, error } }) => (
<ul>
<li>
<button type="button" onClick={() => fields.push({})}>
Add Member
</button>
{touched && error && <span>{error}</span>}
</li>
{fields.map((member, index) => (
<Member member={member} fields={fields} index={index} key={index} />
))}
</ul>
);
const FieldArraysForm = props => {
const { handleSubmit, pristine, reset, submitting } = props;
return (
<form onSubmit={handleSubmit}>
<Field
name="clubName"
type="text"
component={renderField}
label="Club Name"
/>
<FieldArray name="members" component={renderMembers} />
<div>
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
);
};
export default reduxForm({
form: "fieldArrays", // a unique identifier for this form
validate
})(FieldArraysForm);
In order to access the FieldArray dynamically, you would want to change this:
change("FieldArraysForm", `${props.member}.firstName`, this.props.hasLastName)
to this:
change("FieldArraysForm", `members[${this.props.index}].firstName`, this.props.hasLastName)
Also, pass in the form selector specified:
const selector = formValueSelector("fieldArrays");
This would give you:
change("fieldArrays", `members[${this.props.index}].firstName`, this.props.hasLastName)
Had to get some help on this one - thanks goes to #Amanda Field.
You need to specify the index of the field in FieldArray you want to change. To do so, just use <fieldName>.<index>.<propertyName>, for instance:
this.props.change('members.0.firstName', 'Donald')
where member is the name of your FieldArray field, 0 is the index of the item in the array you want to change and firstName is the property of the object.
See sandbox here

On Redux-Form Validations disappear because the actions UNREGISTERED_FIELD/REGISTER_FIELD are triggered (twice)

I am using React 16, Redux-form 7
I have a field with a validation. When I change the value the UPDATE_SYNC_ERRORS is triggered and syncErrors correctly added to the state. Then automatically two series of UNREGISTERED_FIELD/REGISTER_FIELD are triggered and the syncErrors are eliminated and never recreated, even though the value of the field is still incorrect.
<Field
name="afield"
validate={[ required, number, minValue(100) ]}
component={props => <AnInput options={options} {...props} />}
/>
const AnInput = props => {
const {
options: { label, prompt, helpText },
input,
meta: { touched, dirty, error, warning }
} = props;
return (
<div className="form-group">
<label>
{label}
</label>
<div >
<input
{...input}
/>
{touched &&
((error && <span>{error}</span>) ||
(warning && <span>{warning}</span>))}
</div>
{helpText && <FieldHelp title={label} helpText={helpText} />}
</div>
);
};
Actions triggered when field is changed
This is because you are calling a function in the validation.
You should use something like this:
const min100 = minValue(100);
Take a look here https://github.com/erikras/redux-form/issues/3405

unable to set defaultValue in redux-form-material-ui TextField

I'm unable to set a default value for the textField component.
I tried using default value, but as long as I'm using the redux-form-material-ui it just doesn't work.
I really don't understand what am I doing wrong (seems pretty basic)...
exmaple (just changed their fieldArray example a little):
import React from 'react'
import { Field, FieldArray, reduxForm } from 'redux-form'
import validate from './validate'
import {TextField} from 'redux-form-material-ui'
const renderField = (props) => {
console.log(props);
const { input, label, type, meta: { touched, error } } = props;
console.log(input);
return <div>
<label>{label}</label>
<div>
// Will not show "someValue", it will just be blank
<TextField defaultValue="someValue" {...input} type={type} placeholder={label}/>
{touched && error && <span>{error}</span>}
</div>
</div>
}
const renderMembers = ({ fields, meta: { touched, error, submitFailed } }) => (
<ul>
<li>
<button type="button" onClick={() => fields.push({})}>Add Member</button>
{(touched || submitFailed) && error && <span>{error}</span>}
</li>
{fields.map((member, index) =>
<li key={index}>
<button
type="button"
title="Remove Member"
onClick={() => fields.remove(index)}/>
<h4>Member #{index + 1}</h4>
<Field
name={`${member}.firstName`}
type="text"
component={renderField}
label="First Name"/>
<Field
name={`${member}.lastName`}
type="text"
component={renderField}
label="Last Name"/>
<FieldArray name={`${member}.hobbies`} component={renderHobbies}/>
</li>
)}
</ul>
)
const renderHobbies = ({ fields, meta: { error } }) => (
<ul>
<li>
<button type="button" onClick={() => fields.push()}>Add Hobby</button>
</li>
{fields.map((hobby, index) =>
<li key={index}>
<button
type="button"
title="Remove Hobby"
onClick={() => fields.remove(index)}/>
<Field
name={hobby}
type="text"
component={renderField}
label={`Hobby #${index + 1}`}/>
</li>
)}
{error && <li className="error">{error}</li>}
</ul>
)
const FieldArraysForm = (props) => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<Field name="clubName" type="text" component={renderField} label="Club Name"/>
<FieldArray name="members" component={renderMembers}/>
<div>
<button type="submit" disabled={submitting}>Submit</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>Clear Values</button>
</div>
</form>
)
}
export default reduxForm({
form: 'fieldArrays', // a unique identifier for this form
validate
})(FieldArraysForm)
Thanks.
I was having the same issue. Just read through the documentation again and saw this
No Default Values
Because of the strict "controlled component" nature of redux-form, some of the Material UI functionality related to defaulting of values has been disabled e.g. defaultValue, defaultDate, defaultTime, defaultToggled, defaultChecked, etc. If you need a field to be initialized to a certain state, you should use the initialValues API of redux-form.
It's probably only one way to make form of editing.
It cannot be restored from initial redux Form values.
Input
export default function ({ input, label, meta: { touched, error }, ...custom }) {
if ( input.value === '' && custom.cvalue ) { // hack for redux form with material components
input.onChange(String(custom.cvalue));
}
return (
<TextField
{...input}
{...custom}
fullWidth={true}
hintText={label}
floatingLabelText={label}
errorText={touched && error}
/>
)
}
Select
export default function ({ input, label, meta: { touched, error }, onChange, children, ...custom }) {
if ( input.value === '' && custom.cvalue ) { // hack for redux form with material components
if ( is.function(onChange) ) {
onChange(custom.cvalue);
}
input.onChange(custom.cvalue);
}
return (
<SelectField
{...input}
{...custom}
fullWidth={true}
children={children}
floatingLabelText={label}
errorText={touched && error}
onChange={(event, index, value) => {
if ( is.function(onChange) ) { // and custom onChange for f....g ....
value = onChange(value);
}
input.onChange(value);
}}/>
)
}
then in template
its can be way to make form of editing existing entity ....
<Field
name="study"
label="Studies"
component={ FormSelect }
cvalue={this.state.study.id}
onChange={value => {
this.setState({study: _.find(studies, {id: value})||{id: 0}});
return value;
}}>
{studies.map( (study, key) => ( <MenuItem key={key} value={study.id} primaryText={study.officialTitle} /> ))}
</Field>

Resources