REACT: conditionally rendering a alert if field left blank - reactjs

I have the following React form:
import React from 'react';
export default class ChatBar extends React.Component {
mySubmitHandler = event => {
event.preventDefault();
/* you can access the value as below */
const inputName = this.refInputName.value;
const inputEmail = this.refInputEmail.value;
const inputMessage = this.refInputMessage.value;
// const inputStamp = this.convertDate(new Date())
const message = {name: inputName, email: inputEmail, content: inputMessage, stamp: inputStamp}
this.props.addMessage(message)
this.refInputMessage.value = ""
}
render() {
return (
<div>
<h4>Leave a Comment</h4>
<form onSubmit={this.mySubmitHandler}>
<label>Your name
<input
type="text"
name="name"
ref={(node) => (this.refInputName = node)}
/>
</label>
<label>Your email
<input
type="text"
name="email"
ref={(node) => (this.refInputEmail = node)}
/>
</label>
<label>Your message
<textarea ref={(node) => (this.refInputMessage = node)} />
</label>
<br />
<input className="submit-button" type="submit" value="Submit comment" />
</form>
</div>
)
};
};
I need to create a way so that when an input is left black and either submitted or hovered over, it creates a "tool tip" alerting the user the field has been left blank (see attached image). I have tread fooling around with onHover, onClick and onSubmit handlers to render some state of tool tip being "true" and conditionally render the toolTip div however it does not seem to be working and I am rather lost, now starting from scratch again.
Any help is greatly appreciated =)

I recommend react-valida-hook, it's really simple to use, you can add personalized messages, the only thing you need to do is pass the error.
Example:
const displayError = (errs) => {
if (errs.indexOf('required') !== -1) {
return '*Super important required field';
}
if (errs.indexOf('minLength') !== -1) {
return '*Too short man!';
}
if (errs.indexOf('isEmail') !== -1) {
return '*That looks wrong';
}
return '';
};
<div className="errors">
// I use a variable to show only errors wen form is submitted
{submitted && displayError(validation.errors.firstName)}
</div>

You can make two custom CSS class for visibility: hidden, ect.
Then render the toolTip div like such:
<div className="tool-tip" style={this.state.showTip ? visible : hidden}>testing </div>

Related

How to block negative values in Input tags while entering in forms

I am new to React, In my project I have a form with two Input tags, first Input tag is Room number and second Input tag is Amount, What I am trying to achieve is When someone try to enter negative values like -10 or -200 then I have to block those values even it should not appear in Input tags.
Second one is I have to block these kind of values also like 1.2, 3.3, -3.3 even I have to block these values as well it should not appear in Input tags
so someone please help me to achieve this.
This is App.js
import React, { useState } from "react";
import "./App.css";
const App = () => {
const [data, setData] = useState({})
const handleChange = ({ target }) => {
const { name, value } = target
// console.log(name, value)
const newData = Object.assign({}, data, {[name]:value})
setData(newData)
}
const validations = () => {
if(data.room_no && data.amount < 1) {
alert()
}
}
const handleSubmit = (e) => {
e.preventDefault()
console.log(data)
validations()
}
return (
<div className='container'>
<div className='row justify-content-center'>
<div className='col-4'>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="exampleInputEmail1">Room No</label>
<input name="room_no" onChange={handleChange} type="number" className="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter room no" />
</div>
<div className="form-group">
<label htmlFor="exampleInputPassword1">AMount</label>
<input name="amount" onChange={handleChange} type="number" className="form-control" id="exampleInputPassword1" placeholder="AMount" />
</div>
<button type="submit" className="btn btn-primary mt-3">Submit</button>
</form>
</div>
</div>
</div>
)
}
export default App
Our conditions are:
Positive Numbers
Integers only (non-decimals)
We should handle:
Mouse events
Keyboard events
For mouse events, we will cover it with input API as normal HTML element, by using min={0} and step={1}.
For keyboard events, the trick is to prevent press event on invalid input.
So we will try and rewrite this plain HTML as React DOM element:
<input type="number" onkeypress="return event.charCode >= 48" min="0" step="1" />
export default function App() {
return (
<input
type="number"
min={0}
step={1}
onKeyPress={(event) => {
if (event.charCode < 48) {
event.preventDefault();
}
}}
/>
);
}
To block user from entering or pasting the negative values into an input field in react.
add an onKeyPress listener to the input element and call a function that will prevent default behaviour when the minus button is pressed.
To prevent user from pasting the negative values into the input field. Add an onPaste listenerto your input field and to check the clipboard data to see if it's negative and prevent pasting the negative values into the input field.
const preventPasteNegative = (e) => {
const clipboardData = e.clipboardData || window.clipboardData;
const pastedData = parseFloat(clipboardData.getData('text'));
if (pastedData < 0) {
e.preventDefault();
}
};
const preventMinus = (e) => {
if (e.code === 'Minus') {
e.preventDefault();
}
};
<input
type="number"
min="0"
onPaste={preventPasteNegative}
onKeyPress={preventMinus}
/>

React Functional Component: How to prevent form from submitting if validation failed

I need some help, I am new to react. I created a Functional Component form with Context API and I am trying to prevent it from submitting if the form failed validation and return false. I have check the validation and it is working by uncommenting the html input button and comment out the React Link (<Link></Link>) button. I try the code with class component and bind the handleChange and handleSubmit inside the constructor and it work: however, I do not want to used the class component. I just want to used the function component.
const Employee = () => {
const ctx = useContext(FormActualContext);
const handleChange = (event) => {
ctx.handleChange({
event,
type: 'employee',
});
};
const validate = () => {
const {
firstName,
lastName,
email,
dateOfBirth,
phoneNum,
} = ctx.formData.employee;
const { employee } = ctx.formErrors;
let {
firstNameError,
lastNameError,
emailError,
dateOfBirthError,
phoneNumError,
} = employee;
firstNameError = !firstName ? 'First name can not be blank' : '';
lastNameError = lastName === '' ? 'Last name can not be blank' : '';
dateOfBirthError = !dateOfBirth ? 'Enter a valid date of birth' : '';
if (!validateEmail(email)) {
emailError =
email === '' ? 'Enter a valid email' : `${email} is not valid email`;
} else {
emailError = '';
}
if (!validatePhoneNumber(phoneNum)) {
phoneNumError =
phoneNum === ''
? 'Enter a valid phone'
: `${phoneNum} is not a valid phone number`;
} else {
phoneNumError = '';
}
if (
firstNameError ||
lastNameError ||
emailError ||
dateOfBirthError ||
phoneNumError
) {
ctx.setFormErrors({
employee: {
...employee,
firstNameError,
lastNameError,
emailError,
dateOfBirthError,
phoneNumError,
},
});
return false;
}
return true;
};
const handleSubmit = (event) => {
event.preventDefault();
const isValid = validate();
if (isValid) {
ctx.reSetEmployee();
}
};
const {
employee: {
firstNameError,
lastNameError,
emailError,
dateOfBirthError,
phoneNumError,
},
} = ctx.formErrors;
return (
<div className="container_fluid">
<div className="registration_form_container">
<div className="register_context">
<form action="" onSubmit={handleSubmit} className="registration_form">
<div className="form-group">
<input
type="text"
name="firstName"
id="firstName"
placeholder={'Enter first name'}
onChange={handleChange}
/>
<span>{firstNameError}</span>
</div>
<div className="form-group">
<input
type="text"
name="lastName"
id="lastName"
placeholder={'Enter last name'}
onChange={handleChange}
/>
<span>{lastNameError}</span>
</div>
<div className="form-group">
<input
type="text"
name="email"
id="email"
placeholder={'Enter email address'}
onChange={handleChange}
/>
<span>{emailError}</span>
</div>
<div className="form-group">
<input
type="date"
name="dateOfBirth"
id="dateOfBirth"
placeholder={'Enter date of birth'}
onChange={handleChange}
/>
<span>{dateOfBirthError}</span>
</div>
<div className="form-group">
<input
type="text"
name="phoneNum"
id="phoneNum"
placeholder={'Enter phone number (international: +1)'}
onChange={handleChange}
/>
<span>{phoneNumError}</span>
</div>
<div className="form-group custom_btn_container">
{/*<input type="submit" className="btn" value="Register"/>*/}
<Link to="/addressForm">
<input type="submit" className="btn" value="Register" />
</Link>
</div>
</form>
</div>
</div>
</div>
);
};
Issue
The issue isn't that the form is being submitted upon validation (true or false), but rather that both field validation and route navigation are more or less occurring at the same time. The Link, upon being clicked, will immediately navigate to the specified path.
Solution
Seems you want to validate the input, and only upon successful validation, call the reSetEmployee function on the context and navigate to "/addressForm".
I suggest rendering the submit button not within a Link and use imperative navigation. For this I'm assuming you are using react-router-dom library.
import { useHistory } from 'react-router-dom';
...
const history = useHistory();
...
const handleSubmit = (event) => {
event.preventDefault();
const isValid = validate();
if (isValid) {
ctx.reSetEmployee();
history.push("/addressForm");
}
};
...
<div className="form-group custom_btn_container">
<input type="submit" className="btn" value="Register"/>
</div>

Submit form on enter form react component child

I have a unique scenario where I want to check for an enter keypress and tell the parent component to run the submit function. It looks like this.
The onClick={this.props.onSubmitForm} works but I can't get it to submit when the enter key is pressed.
Thanks
Search Component
class Search extends React.Component {
_handleKeyDown = (e) => {
if (e.key === 'Enter') {
this.props.onSubmitForm
}
}
render() {
return (
<div className="searchContainer">
<label>
<p>Search</p>
<input
type="text"
value={this.props.value}
onChange={this.props.onChangeValue}
onKeyDown={this._handleKeyDown}
className="searchBox" />
</label>
<div className="searchButton" onClick={this.props.onSubmitForm}>
>
</div>
</div>
)
}
}
export default Search;
Parent
handleSearchSubmit = (e) => {
if (this.state.value != '') {
this.searchLocation(this.state.value)
}
}
handleSearchSubmit = (e) => {
if (this.state.value != '') {
this.searchLocation(this.state.value)
}
}
<Search
value={this.state.value}
onChangeValue={this.handleChangeValue}
onSubmitForm={this.handleSearchSubmit}
/>
You're just telling, but not calling it here:
this.props.onSubmitForm
You have to do:
this.props.onSubmitForm()
to call the function. Also, a better way of detecting Enter is:
var code = e.which || e.keyCode;
if (code == 13) {
this.props.onSubmitForm();
}
Also, a much better way and right way without using the above logic is to wrap the form elements inside <form> tag and attach the onSubmit handler like this (thanks to Gayatri Dipali's comment on my answer):
<form className="searchContainer" onSubmit={this.props.onSubmitForm}>
<label>
<p>Search</p>
<input
type="text"
value={this.props.value}
onChange={this.props.onChangeValue}
onKeyDown={this._handleKeyDown}
className="searchBox" />
</label>
<button type="submit" className="searchButton">
>
</button>
</div>

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>

on submit form, couldn't get react-select values

onSubmit(values) {
console.log("i m clicked", values); /// i didn't get form values
here.
}
renderMacros() {
const { handleSubmit } = this.props;
const macrosData = this.props.macros.macros;
const categoryMacrosData = this.props.categoryMacros.category;
console.log("categoryMacrosData", categoryMacrosData);
const { open } = this.state;
if (macrosData) {
return (
<div>
<div className="form-block-5 w-form">
<form
id="macros-form"
name="macros-form"
onSubmit={handleSubmit(this.onSubmit)}
>
<div className="row">
<div className="col-sm-12">
<label>Type</label>
<Field // this works fine
name="category"
options={MACRO_TYPE_CATEGORIES}
placeholder="Type"
component={SelectInput}
set_default="true"
/>
</div>
<div className="col-sm-12">
<Field // this works fine
name="name"
placeholder="Name Ex. Follow-up template"
component={renderField}
type="text"
className="text-fields w-input"
id="macros_name"
/>
</div>
<div className="col-sm-12">
<Field // here is the problem
type="text"
name="categoryId"
options={categoryMacrosData}
placeholder="Search or add category "
component={AsyncMulti}
handleSelect={this.handleSelectChange}
/>
</div>
</div>
<button>Create Macro</button>
</form>
</div>
</div>
);
}
}
Bottom line is if i use Creatable component of react-select library, i
couldn't get selected values.
My component file: components/Multi.js
import React from "react";
import CreatableSelect from "react-select/lib/Creatable";
const MultiSelect = props => {
const { options, handleSelect } = props;
return <CreatableSelect isMulti onChange={handleSelect} options=
{options} />;
};
export default MultiSelect;
I am using react-select for select options in redux form. After
submitting form, I am unable to get form submitted values.
I am using react-select library https://react-select.com/creatable with redux form.
Given a props name in <Select> like
<Select
name = {"inputName"} // <- if you submit the form you will get vale like {"inputName":test111}
options = {[{ value: 'test111', label: 'Chocolate' }]}
/>
You are not binding handleSubmit properly as well not using refs since you are not getting the values.
I suggest you to try with the binding code in your <form> tag:
<form
id="macros-form"
name="macros-form"
onSubmit={this.handleSubmit.bind(this)}
>
Also pass refs in your field tag to get the value:
<Field
name="categoryId"
options={categoryMacrosData}
placeholder="Search or add category "
component={Multi}
handleSelect={this.handleSelectChange}
ref="categoryId"
/>
Instead of writing onSubmit function:
onSubmit(values) {
console.log("i m clicked", values); /// i didn't get form values
here.
}
Replace it with this function code:
handleSubmit(event) {
if (this.refs.categoryId !== '') {
event.preventDefault();
console.log('categoryId: ', this.refs.categoryId.value)
}
}
Hope it helps you!

Resources