Use combineValidators for SelectInput to validate Guid.Empty - reactjs

I am looking for a way to validate Select Input before submit final form in React App, I tried below but not working :
When I print the values in handle submit for each is : 00000000-0000-0000-0000-000000000000
How can add the validation error when the Guid is empty
Added in the Final form file react .tsx :
const validate = combineValidators({
projectId: isRequired("The project"),
achievementStageId: isRequired("The project item achievement stage"),
projectItemStatusId: isRequired("The project item status"),
});
<Form onSubmit={handleSubmit} loading={loading}>
<Field
name="projectId"
placeholder="Select Project"
component={SelectInput}
options={projectsDdl}
multiple={true}
/>
<Field
name="achievementStageId"
placeholder="Select Achievement Stage"
component={SelectInput}
options={achievementStagesDdl}
multiple={true}
/>
<Field
name="projectItemStatusId"
placeholder="Select Project Item Status"
component={SelectInput}
options={projectItemStatusDdl}
multiple={true}
/>
projectsDdl, achievementStagesDdl, projectItemStatusDdl as array from APIs
And the component={SelectInput}
import React from "react";
import { FieldRenderProps } from "react-final-form";
import { FormFieldProps, Form, Label, Select } from "semantic-ui-react";
interface IProps extends FieldRenderProps<string, any>, FormFieldProps {}
const SelectInput: React.FC<IProps> = ({
input,
width,
options,
placeholder,
meta: { touched, error },
}) => {
return (
<Form.Field error={touched && !!error} width={width}>
<Select
value={input.value}
onChange={(e, data) => input.onChange(data.value)}
placeholder={placeholder}
options={options || []}
/>
{touched && error && (
<Label basic color="red">
{error}
</Label>
)}
</Form.Field>
);
};
export default SelectInput;

Related

MUI v5: How can I auto focus form inputs with errors?

I am trying to make my form accessible.
Here is my sandbox link: https://codesandbox.io/s/typescript-material-ui-textfield-forked-0xh13?file=/src/App.tsx
My requirements are the following:
Upon submitting a form with validation errors, the 1st input with an error should be focused
Exactly like this form: https://a11y-guidelines.orange.com/en/web/components-examples/forms/
Is there an option in material ui to achieve this?
This is my code:
import React from "react";
import TextField from "#mui/material/TextField";
import { Form, Field } from "react-final-form";
const required = (value: string) =>
value ? undefined : "This field cannot be blank";
const App = () => (
<Form
onSubmit={(form_data) => console.log(form_data)}
render={({ handleSubmit, submitting }) => (
<form onSubmit={handleSubmit}>
<Field
name="line1"
validate={required}
render={({ input, meta }) => (
<TextField
{...input}
placeholder="Required"
label="Required"
helperText={meta.error}
error={meta.touched && meta.error}
/>
)}
/>
<Field
name="line2"
render={({ input, meta }) => (
<TextField
{...input}
placeholder="Optional"
label="Optional"
helperText={meta.error}
error={meta.touched && meta.error}
/>
)}
/>
<button onClick={handleSubmit}>Save</button>
</form>
)}
/>
);
export default App;
I ended up using a plugin for react-final-form called final-form-focus. I don't think there's anything for MUI
https://codesandbox.io/s/typescript-material-ui-textfield-forked-vep9e?file=/src/App.tsx

ReactJS Formik display error message in Red color

In ReactJS i am developing one Class component and using Formik for validation. I am able to do validation but error message is display as a normal color (black). How to add this error message inside any HTML element (span, div,etc..).
Below is the code to validation
import React, { Component } from 'react'
import { useFormik } from 'formik';
import { Formik, FormikProps, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
export class SubmitCase extends Component {
handleSubmit = (values, {
props = this.props,
setSubmitting
}) => {
setSubmitting(false);
return;
}
render() {
const formFields = {...this.state};
return (
<Formik
initialValues={{
subject: formFields.subject
}}
validate={(values) => {
let errors = {};
if(!values.subject)
errors.subject = "subject Required";
//check if my values have errors
return errors;
}
}
onSubmit={this.handleSubmit}
render={formProps => {
return(
<Form>
<Field type="text" placeholder="First Name" name="subject" value={formFields.subject} onChange={this.changeEventReact}/>
<ErrorMessage name="subject" />
<button type="submit">
Submit Form
</button>
</Form>
);
}}
/>);
}
}
I am using to display the message. Error message is displaying as a normal text(black color text). how to change it to red color.
Form formik docs <ErrorMessage> component accepts a children prop as a function children?: ((message: string) => React.ReactNode)
so you can achieve what you want by return a component that wraps error message like this
<ErrorMessage name="subject">
{ msg => <div style={{ color: 'red' }}>{msg}</div> }
</ErrorMessage>
Also you can make css file for example - ErrorMessage.css
with body:
.validation-error-message {
color: red;
}
And make js file for example - validators.js
with body:
import './ErrorMessage.css';
export const ErrorMessageWrapper = (msg) => {
return (
<div className='validation-error-message'>
{msg}
</div>
)
}
And import, and use:
<ErrorMessage name="newPostText">
{ErrorMessageWrapper}
</ErrorMessage>
You can use component props with your custom classes in ErrorMessage.
Formik docs
e.g.
<ErrorMessage component="div" name="name" className="help-block errors" />
<ErrorMessage component="div" name="email" />
// --> {touched.email && error.email ? <div>{error.email}</div> : null}
<ErrorMessage component="span" name="email" />
// --> {touched.email && error.email ? <span>{error.email}</span> : null}
<ErrorMessage component={Custom} name="email" />
// --> {touched.email && error.email ? <Custom>{error.email}</Custom> : null}
<ErrorMessage name="email" />
// This will return a string. React 16+.
// --> {touched.email && error.email ? error.email : null}

Unable to make the Checkbox work with redux-form and react-semantic-ui

I'm trying to use redux-form with react-semantic-ui and is having trouble with the Checkbox component. The Checkbox is not being checked. I've followed the example from the redux-form documentation, but no luck. Here's the Code snippet :
renderCheckBox = ({ input, label }) => {
console.log(input.value);
return (
<Form.Field>
<Checkbox
label={label}
checked={input.value ? true : false}
onChange={input.onChange}
/>
</Form.Field>
);
};
<Field
name="activated"
label="Activate?"
component={this.renderCheckBox}
/>
The output of console.log(input.value) is empty.
Reusable redux form checkbox with semantic ui
import React from 'react';
import { object } from 'prop-types';
import { Field } from 'redux-form/immutable';
import { Checkbox as CheckboxUI } from 'semantic-ui-react';
const Checkbox = ({
input: { value, onChange, ...input },
meta: { touched, error },
...rest
}) => (
<div>
<CheckboxUI
{...input}
{...rest}
defaultChecked={!!value}
onChange={(e, data) => onChange(data.checked)}
type="checkbox"
/>
{touched && error && <span>{error}</span>}
</div>
);
Checkbox.propTypes = {
input: object.isRequired,
meta: object.isRequired
};
Checkbox.defaultProps = {
input: null,
meta: null
};
export default props => <Field {...props} component={Checkbox} />;
How to use?
import Checkbox from './Checkbox';
<form>
...
<Checkbox name="example" />
...
</form>
If you want to know whether the checkbox is checked or not, you have to use
onChange={(e, { checked }) => input.onChange(checked)}
instead of
onChange={input.onChange}
Here's a working example

ReactJS: How to wrap react-select in redux-form field?

I am working on react-select library and facing some issues, I am using redux-form library and importing <Field /> component from it. So that I can submit the values via form to service.
Below mentioned code works fine, when I use default <Select> from react-select. I can able to select the values from the drop down and the value will be selected even on focus out the value will remain. But selected value is not submitting via form due to redux-form that's why I am wrapping <Select /> component and using with <Field name="sample" component={RenderSelectInput} id="sampleEX" options={options} />
import React from 'react';
import Select from 'react-select';
import RenderSelectInput from './RenderSelectInput'; // my customize select box
var options = [{ value: 'one', label: 'One' }, { value: 'two', label: 'Two' }];
class SelectEx extends React.Component {
constructor() {
super();
this.state = { selectValue: 'sample' }
this.updateValue = this.updateValue.bind(this);
}
updateValue(newValue) {
this.setState({ selectValue: newValue })
}
render() {
return (
<div>
<Select name="select1" id="selectBox" value={this.state.selectValue} options={options} onChange={this.updateValue}/>
//This works but value won't submit ...
<Field name="sample" component={RenderSelectInput} id="sampleEX" options={options} />
//For this, selected value vanishes once I come out of component.
</div>
)
}
}
export default SelectEx;
But when I use with my customized select (I am wrapping the to submit the value from form) the <Select> component can be visible in UI even the values also. But unable to select the value from dropdown ..., If I select also it displays in the <Select> box but on focus out it vanishes. Please help me ...
RenderSelectInput component:
import React from 'react';
import {Field, reduxForm} from 'redux-form';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
const RenderSelectInput = ({input, options, name, id}) => (
<div>
<Select {...input} name={name} options={options} id={id} />
</div>
)
export default RenderSelectInput;
When using react-select with redux-form, you'll need to change the default behavior of onChange and onBlur method and call redux-form's onChange and onBlur method respectively.
So, Try this:
const RenderSelectInput = ({input, options, name, id}) => (
<Select
{...input}
id={id}
name={name}
options={options}
value={input.value}
onChange={(value) => input.onChange(value)}
onBlur={(value) => input.onBlur(value)}
/>
)
and use the above component like
<Field component={RenderSelectInput} />
Calling redux-form's onBlur method when focus is removed from the Select field will prevent loss of value.
Here this worked for me,
import React, { Component } from 'react';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
export default class RenderSelectInput extends Component {
onChange(event) {
if (this.props.input.onChange && event != null) {
this.props.input.onChange(event.value);
} else {
this.props.input.onChange(null);
}
}
render() {
const { input, options, name, id, ...custom } = this.props;
return (
<Select
{...input}
{...custom}
id={id}
name={name}
options={options}
value={this.props.input.value || ''}
onBlur={() => this.props.input.onBlur(this.props.input.value)}
onChange={this.onChange.bind(this)}
/>
);
}
}
this was extracted from here: https://ashiknesin.com/blog/use-react-select-within-redux-form/
Use this which works perfectly and it also handles redux form validation.
import React, {Component} from 'react';
import Select from 'react-select';
import {FormGroup} from "reactstrap";
class CustomSelect extends Component {
render() {
const {meta: {touched, error}} = this.props;
const className = ` form-group mb-3 ${touched && error ? 'has-danger' : '' }`;
return (
<FormGroup>
<Select
{...this.props}
value={this.props.input.value}
onChange={(value) => this.props.input.onChange(value)}
onBlur={() => this.props.input.onBlur(this.props.input.value)}
options={this.props.options}
placeholder={this.props.placeholder}
/>
<div className={className}>
<div className="text-help">
{touched ? error : ''}
</div>
</div>
</FormGroup>
);
Use the CustomSelect component in redux form field component as
<Field
name='country_name'
options={this.state.countries}
component={CustomSelect}
placeholder="Select your country"
/>
I had to call the onBlur without any argument. The issue with Hardik's answer was, it was not working in iPad (May be also in other iOS or touch devices. I was unable to check).
The onBlur event is automatically triggered along with the onChange event in iPad. It caused the select value to reset to its initial value. So I had to call onBlur method like this,
onBlur={(value) => input.onBlur()}
const RenderSelectInput = ({input, options, name, id}) => (
<Select
{...input}
id={id}
name={name}
options={options}
value={input.value}
onChange={(value) => input.onChange(value)}
onBlur={(value) => input.onBlur()}
/>
)
and used as,
<Field component={RenderSelectInput} />
Try setting onBlurResetInput property to false.
Something like.
const SelectInput = ({input: { onChange, value }, options, name, id}) => (
<Select
name={name}
value={value}
options={options}
onChange={onChange}
onBlurResetsInput={false}
/>
)
Hope this helps!

want to load initial Values in Redux Form

i am trying to load the initial value in from but couldn't do this, i am using redux-from, i set the profile data in redux store and can access the data through the props(console them) but can't able to show in the form input. i am trying to replicate this redux-from example. but couldn' able to continue it.
below is the code.
import React from 'react';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { required, email, maxLength25 } from '../utils/validations';
import { renderField,
renderSelectField,
renderRadioField,
renderTextAreaField,
renderCheckboxField
} from '../utils/textFieldGroup';
import countries from '../utils/countryList';
import { profileUpdate, profile } from '../actions/user';
const validateAndUpdateRecords = (values, dispatch) => {
return dispatch(profileUpdate(values))
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
})
}
class ProfileForm extends React.Component {
componentWillMount(dispatch){
console.log('mount');
this.props.fetchProfile();
}
render(){
const { handleSubmit, submitSucceeded, error, profile } = this.props
console.log('prof',profile);
return (
<div>
<h1>Profile Page</h1>
<form onSubmit={handleSubmit(validateAndUpdateRecords)}>
<div className={typeof error!='undefined'?'show alert alert-danger': 'hidden'}>
<strong>Error!</strong> {error}
</div>
<Field name="fname" type="text" component={renderField} label="First Name"
validate={[ required, maxLength25 ]}
/>
<Field name="lname" type="text" component={renderField} label="Last Name"
validate={[ required, maxLength25 ]}
/>
<Field component={renderRadioField} name="gender" label="Gender" options={[
{ title: 'Male', value: 'male' },
{ title: 'Female', value: 'female' }
]} validate={ required } />
<Field name="country" type="text" data={countries} component={renderSelectField} label="Country"
validate={[ required ]}
/>
<Field name="about_us" type="text" component={renderTextAreaField} label="About Us"
validate={[ required ]}
/>
<Field name="newsletter" type="checkbox" component={renderCheckboxField} label="Newsletter"
validate={[ required ]}
/>
<p>
<button type="submit" disabled={submitSucceeded} className="btn btn-primary btn-lg">Submit</button>
</p>
</form>
</div>
)
}
}
ProfileForm = reduxForm({
form:'profile'
})(ProfileForm)
ProfileForm = connect(
state => ({
initialValues: state.user.profile
})
)(ProfileForm)
export default ProfileForm;
//text field
export const renderField = ({ input, label, type, meta: { touched, error, warning } }) => (
<div className={classnames('form-group', { 'has-error':touched && error })}>
<label className="control-label">{label}</label>
<div>
<input {...input} placeholder={label} type={type} className="form-control"/>
{touched && ((error && <span className="help-block">{error}</span>))}
</div>
</div>
)
Thanks in advance
Finally i figure out the solutions. below is the solutions. We need to add enableReinitialize : true as mentioned below. If our initialValues prop gets updated, form will update too.
ProfileForm = reduxForm({
form:'profile',
enableReinitialize : true
})(ProfileForm)

Resources