React client side validation with material-ui component - reactjs

Some material-ui components have errorText as a prop which we can use to show errors, But, doing that in react become lot complex if my form has large number of field components.
Please suggest the best way to handle client-side validation with material-ui comonents.

I think your issue is that you have to manage a lot with state/store. In react validation is complex because of one-way binding.
This library https://github.com/vishalvisd/react-validator is one which I found that supports material-ui component validation. Though in general you may use this to validate any component.

I would suggest using some HoC (Higher-order Component) approach. I tested many solutions for form validation in React JS, the one that I always choose is: react-validation-mixin. Take a look at this example.
Example of the standard input:
<input
type='text'
placeholder='Username'
value={this.props.username}
onChange={this.onChange('username')}
onBlur={this.props.handleValidation('username')}
/>
In this example value of that input comes from props (example with Flux implementation) and that's probably what you aim for too (lots of inputs).
onChange will need to handle value change so that this.props.username gets updated too and onBlur will trigger validation check (so that the error will show up once user leaves the input).
In order to get the error message, use: this.props.getValidationMessages('username')
It's a universal solution and you can use it in different libs. But taking TextField from material-ui, as you asked:
<TextField
floatingLabelText="Username"
value={this.props.username}
errorText={this.props.getValidationMessages('username')}
onChange={this.onChange('username')}
onBlur={this.props.handleValidation('username')}
...
/>
Remember to use HoC with your component: export default validation(strategy)(UserLogin) That way, you will get all the necessary helper methods in props.

If you are using Redux in React project, redux-form give you a simple way to implement form validation.
Check this out: http://redux-form.com/6.4.3/examples/syncValidation/

Related

How to use soft validation (aka tips or warning messages) in React Hook Form v7

What I'm trying to do:
I'm building a complex form and need a way to provide tips and warning messages based on certain conditions (mostly regex) without blocking form submission. Essentially the messages will act as a form of soft validation to help the user complete a higher quality form. I would like to find a solution that plays well with React Hook Form V7.
The Problem:
React Hook Form V7 only supports hard validation (aka blocks form submission). From what I can tell there's no plan to add support this feature in the near future according to this rhf feature request.
Possible Solutions:
There are some V6 solutions proposed in the above rhf feature request such as this one from the creator of rhf:
Using a custom Power Controller (Sandbox), (https://www.youtube.com/watch?v=Vkiyg_KfNK4&t=14s)
const PowerController = (props: Props) => {
const { formState } = useFormContext();
const isDirty = !!formState.dirtyFields[props.name];
const isTouched = !!formState.touched[props.name];
return (
<Controller
control={props.control}
name={props.name}
defaultValue={props.defaultValue}
render={(innerProps) => {
return props.render({
...innerProps,
isDirty,
isTouched,
warning: props.warn(innerProps.value)
});
}}
/>
);
};
However, I've been unable to get this to work with V7 Controller
I also found this answer on how to trigger custom onChange with rhf and the suggestion was to pass an onChange to Controller or to useWatch(). Link here.
I like passing the custom onChange to Controller solution but if I understand right doing so would replace the onChange that's built into Controller. I'm not sure how to make this work since I'm just trying to add some functionality (aka soft validation on field change).
The solution of useWatch() to see when the value changes then have a separate useEffect() that I place my soft validation logic in seems reasonable but in a complex form might get real messy??
What I need help with:
Any suggestions on which approach is best and/or ideas on how to adapt the Power Controller V6 solution to work with the V7 Controller would be appreciated. I'm just learning rhf and hoping to get some input before I spend weeks banging my head against a wall trying to solve this lol.
I struggled with the same thing and found out that refactoring the proposed codesandbox solution to work with rhf v7 is not that hard (the sandbox messages when upping the version were actually helpful.
Here is a forked version, I hope it helps -
https://codesandbox.io/s/extend-controller-forked-v7-upgrade-iyw5p0?file=/src/App.tsx

Reactjs Antd library and google maps Places

My team and I have been using Antd a react component library. I was asked to connect google.map's Places library to an input field so we can get an easy address drop-down list.
The problem is the Antd's input component is wrapped up under the hood. So when I click on an address from google.maps Places menu it appears in the input field for a milli sec then disappears.
I tried all the event.preventDefault(), event.stopPropoagtion(). Is there any trick to combining google.maps places returned data with a well nested react-ui component?
(too long for comment)
I have the exact same problem.
I'm using NextJS with functional component and #react-google-maps/api library.
The workaround I use: simple <input> element combined with the right CSS class to make it look like the Antd <Input>.
Like this:
<LoadScript
googleMapsApiKey={process.env.NEXT_PUBLIC_GOOGLE_MAP_API_KEY}
libraries={libraries}
>
<Autocomplete
onLoad={(autocomplete) => setAutocomplete(autocomplete)}
onPlaceChanged={onPlaceChanged}
restrictions={{ country: "fr" }}
fields={['geometry.location', 'formatted_address']}
>
<input
type="text"
placeholder="Enter your address"
className="ant-input"
/>
</Autocomplete>
</LoadScript>
This way, when clicking on an address from Places menu, its value stays in the input field.
If anyone has a better and less hacky solution, I'm looking for one!
This is a very simple matter of state management. It sounds like the google-places input field was working correctly or it wouldn't have shown up at all. If your input field is connected to let's say Reactjs then you will need to add the google-places response data to your state-management and it should stop disappearing. This happens a lot when companies use custom state-management systems.

Why using value for input in react

<input value={name.firstName} onChange={e => setName({firstName : e.target.value})} />
Even if we remove the value and use this code:
<input onChange={e => setName({firstName : e.target.value})} />
The app still works. What is the difference?
Second question, Do you think the hooks will be used as default for React to use? Will context api be replacement for redux in close future?
It's better to use value attribute, because if some error is thrown while setting a value, user will see it. For example, if value stops being stored in a state, the input will stop too. If you don't use value tag, input won't stop in that case.
NO. In react docs, we read "We intend for Hooks to cover all existing use cases for classes, but we will keep supporting class components for the foreseeable future. At Facebook, we have tens of thousands of components written as classes, and we have absolutely no plans to rewrite them. Instead, we are starting to use Hooks in the new code side by side with classes."
ContextAPI won't replace redux because of few big reasons. You don't have time travel debugger or configurable middleware.
Also you can read this article

React, Reactstrap - Input vs input, form-control class prevents values from submitting, returns undefined

I am working on an basic React CRUD App and I came across a strange issue.
Using Reactstrap Input Component or the bootstrap class="form-control" the input values are undefined onSubmit.
If I leave the elements as a standard html input the values submit just fine?
I cannot figure out why this is happening.
I put together this demo that illustrates the issue.
Code Sandbox Snippet <- Live Demo
On the AddName.js file I have one Input and one input on submit you can see that the first name submits but the description does not.
<FormGroup>
<input
placeholder="First Name"
ref={nameInput => (this.nameInput = nameInput)}
/>
</FormGroup>
<FormGroup>
<Input
placeholder="Description"
ref={descriptionInput => (this.descriptionInput = descriptionInput)}
/>
</FormGroup>
Can anyone explain why this is happening? Is it possible how I have the refs on the inputs?
Before utilizing 3rd party packages, you should read into using Controlled Components strictly through React. Then, once you understand the flow, incorporate the packages.
I've rewritten your project to include all of the above, as well as written notes describing what I changed and why. There are also a few tricks and shortcuts I've used to simplify the code, such as: setState callback, ES6 Object Deconstruction and Fat Arrow Functions.
Working example: https://codesandbox.io/s/l9m0vor4wq
You should only need to use refs for obtaining a DOM element or a class instance for UI manipulation, instead of obtaining a data value. For example, utilizing a ref to draw attention to a DOM element via using its focus() method or removing attention from it via its blur() method. In your case, we would only use the synthetic event instead of a ref.
On a side note, be careful about using the name as a key in <PersonCard/>, because multiple users can share the same name value. This will cause React to complain that two keys are the same, and cause issues if you ever try to remove, resort, or filter the names list. To keep it simple, I instead used the key provided by the map function. While this approach works, it's not the best solution. Ideally, each person should have an id property with a UUID. This ensures all of your keys will be unique.

react willReceiveProps workaround for external library

I'm using a react datepicker component that can be found here. The component is pretty great except for what appears to be an oversight: it does not implement willReceiveProps.
To expound, I create the datpicker as below:
<DateField
dateFormat= { dateFormat}
forceValidDate={true}
defaultValue={startDate || ''}
onChange={this.handleChange.bind(null, 'start_date')}
id="start"
>
<DatePicker
navigation={true}
locale="en"
forceValidDate={true}
highlightWeekends={true}
highlightToday={true}
weekNumbers={true}
weekStartDay={0}
/>
</DateField>
Note above that there is a prop defaultValue which I pass startDate. Now, startDate can and does change for reasons that are sometimes external to the component. That value is passed during a new render() action as per usual. According to react philosophy this shouldn't be a problem.
However, it appears to me as if the value from defaultValue is only ever read once inside DateField. It is read as this.props.defaultValue. Anyone who has ever built a component relying on props should quickly recognize this is a problem. It means that when the prop is changed the new value will not be used.
Because this is a library, I cannot simply implement willReceiveProps. Does anyone know of a good workaround to get this component to either completely reset on a render or some other strategy to deal with what seems to be a big design problem?
They follow the same standards as the <input> component. defaultValue is read only once but there is also value that can be set externally. There is no need for them to use willReceiveProps.
In short, use value instead of defaultValue.
See Uncontrolled Components in React
PS: I am looking a bit into the code and it seems there are also properties text and date apart from value. Since the code (and documentation) has been removed from github, I won't inspect what is the difference between those props.

Resources