React - Set input number value conditionally - javascript

I have 2 input type number fields and I'm trying to set the second field value(num2) conditionally based on the first one's(num1) value.
<input ref="num1" type="number" min="1" max="7" defaultValue={6}/>
<input ref="num2" type="number" min="0" max={this.refs.num1 === 7 ? 0 : 10} defaultValue={10}/>
I've tried the above ternary operator to set value 0 if num1's value is equal to 7. The default value for num1 is 6 and when I stepup to 7, there is no different I can see in num2.
Please help me fix this.

Try validating by using onChange event in the input
<input onChange={this.onChange} />
And create a method onChange with womthing like:
onChange(e) {
let value = e.target.value;
return validation;
}

I'm not sure if I understand what you want, but you can try something like this :
class Test extends React.Component {
constructor(props){
super(props);
this.state = {
num1: null
}
}
onChange(num, e){
this.setState({num1: e.target.value});
}
render(){
return(
<div>
<input type="number" min="1" max="7" defaultValue={6} value={this.state.num1} onChange={this.onChange.bind(this, "num1")}/>
<input type="number" min="0" max={10} value={this.state.num1 == 7 ? 10 : 0} />
</div>
);
}
}
React.render(<Test />, document.getElementById('container'));
Add state to your component and then change the value of the first input via an onChange function.
Then depending on that value show value of the second input.
Here is a fiddle.

Related

Hande input onChange event in dynamic react js form

I have a Form component with a title input and a dynamic number of ingredient inputs (the user can add and remove them with corresponding buttons). Most of the form functions properly. However, I receive a warning that I have passed a value prop to a form field without an onChange handler for the ingredient input element(s).
In render() for my Form component, this part should dynamically generate inputs (EDIT: by mapping from an array of ingredients in my Form's state):
{this.state.ingredients.map((element, i) => {
return (
<div key={i}>
<input
type='text'
placeholder='new ingredient'
value={element || ''}
onChange={this.handleIngredientChange.bind(this)}
/>
</div>
);
})}
I thought these inputs would connect to my handleIngredientChange method to update the state of the ith ingredient name when the user changes the input value:
handleIngredientChange(i, event) {
let ingredients = [...this.state.ingredients];
ingredients[i] = event.target.value;
this.setState({ingredients});
}
And that this method would appropriately allow react to control each input element.
I seem to be misunderstanding this and/or .bind(), because I clearly assigned onChange={this.handleIngredientChange.bind(this)} to the ingredient input element in my map function. When the user types in one of these inputs, we get `TypeError: undefined is not an object (evaluating 'event.target').
Perhaps the root of the problem is that when the user types in the input, handleIngredientChange is not correctly set up to get the user's desired input value, but I cannot see where the error is.
I have looked at a lot of similar questions and have tried to implement their answers to no avail. Could anyone point me in the right direction on why I have not handled the onChange event properly? I'd be more than happy to explain my intentions further if you need me to. Many thanks in advance.
Full code:
export default class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
title: '',
ingredients: [],
};
}
handleTitleChange(event) {
let title = this.state.title;
title = event.target.value;
this.setState({title});
}
handleIngredientChange(i, event) {
let ingredients = [...this.state.ingredients];
ingredients[i] = event.target.value;
this.setState({ingredients});
}
removeClick(i) {
let ingredients = [...this.state.ingredients];
ingredients.splice(i, 1);
this.setState({ingredients});
}
addClick() {
let ingredients = [...this.state.ingredients];
ingredients.push('');
this.setState({ingredients});
}
handleSubmit(event) {
console.log('submit request logged')
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
placeholder='recipe title'
value={this.state.title || ''}
onChange={this.handleTitleChange.bind(this)}
/>
{this.state.ingredients.map((element, i) => {
return (
<div key={i}>
<input
type='text'
placeholder='new ingredient'
value={element || ''}
onChange={this.handleIngredientChange.bind(this)}
/>
</div>
);
})}
<input
type='button'
value='add'
onClick={this.addClick.bind(this)}
/>
<input
type='Submit'
value='save'
onClick={this.handleSubmit.bind(this)}
/>
</form>
)
}
}
I'm not sure if this helps
try change
<input
type="text"
placeholder="new ingredient"
value={element || ""}
id={i}
onChange={this.handleIngredientChange.bind(this)}
/>
and then alter
handleIngredientChange(event) {
let ingredients = [...this.state.ingredients];
ingredients[event.target.id] = event.target.value;
this.setState({ ingredients });
}
https://codesandbox.io/s/react-playground-forked-yf7rpm

Change input value with useRef

I captured an element with the useRef hook of React.
if I use console.log(this.inputRef) I get:
<input aria-invalid="false" autocomplete="off" class="MuiInputBase-input-409 MuiInput-input-394" placeholder="Type ItemCode or scan barcode" type="text" value="2">
Is there a way to change the value of that element using this.inputRef? and then force its re-render?
It sounds like what you are looking for is the ImperativeHandle hook.
From React docs:
useImperativeHandle customizes the instance value that is exposed to parent components when using ref
The below code should work for you:
function ValueInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
changeValue: (newValue) => {
inputRef.current.value = newValue;
}
}));
return <input ref={inputRef} aria-invalid="false" autocomplete="off" class="MuiInputBase-input-409 MuiInput-input-394" placeholder="Type ItemCode or scan barcode" type="text" value="2">
}
ValueInput = forwardRef(ValueInput);
Documentation: https://reactjs.org/docs/hooks-reference.html#useimperativehandle
well, you could do:
<input ref={myRef} value={myRef.current.value} />
The only problem with that is that refs DO NOT update or reredender the component, so, the value would never update... rather than that it could throw you an error where you are attempting to make an uncontrolled input as controlled
may be this can help
return(
<input type="text" ref={inptRef} />
<button onClick={()=>inptRef.current.value = ""}>clear input</button>
)

Why after onClick my hook is failing to update the state?

I have defined a constant to use UseState Hook in ReactJS by:
const [inputValue, setInputValue] = useState("")
Using the inputValue for my form in a way:
<form
data-testid="form"
onSubmit={e => {
e.preventDefault();
setLogFilters({
queryText: inputValue
});
}}
>
I am able to input string in my form using the snippet below:
<Input
name="input1"
type="text"
onChange={e => setInputValue(e.target.value)}
/>
I now have a button which onclick should clear the string input in the form:
<Button
onClick={() => {
setInputValue("");
}}
>
But the form retains the original string and the state is not set to null string. What is wrong? why is the hook not able to update the state?
As mention by #Corentin when you have any input field and you want its value to get change when you write something, you need to have a state for that, just like you have a state with name inputValue
you need to bind this state with your input through value prop i.e
<Input
//This will change your input when your state will be updated
value = {inputValue}
name="input1"
type="text"
onChange={e => setInputValue(e.target.value)}
/>
Now, the value will get change when you will set your inputValue state.
your input field does not have the value attribute, it should be like below:
<Input
name="input1"
type="text"
value={inputValue}
onChange={e => setInputValue(e.target.value)}
/>
For change the value of an input with hooks, you've to initialize your state like "value" in your input.
Example :
function onClick () {
setYourState('Blabla')
}
<input placeholder='Enter blabla' value={yourState} onChange={(e) => setYourState(e.target.value)}></input>

Maxlength does not work React Js

I have an input with React, but maxlength does not work. Does anyone know how to solve this?
This is handleChangeInput
handleChangeInput(input) {
this.setState({
...this.state,
form: {
...this.state.form,
[input.target.name]: input.target.value
}
})
}
And this is my input:
<div className="input-field col s12 m6 l6">
<input onChange={this.handleChangeInput} value={this.state.form.message} type="text" className="phone validate" name="phone" maxlength="11"/>
<label for="telefone">Telefone</label>
</div>
Property and attribute names are generally camelCase in React, maxLength works.
<input
onChange={this.handleChangeInput}
value={this.state.form.message}
type="text"
className="phone validate"
name="phone"
maxLength="11"
/>
However, you can still override this option if you give the input a value longer than maxLength. The only way around this is to check the length of the value in the callback, and truncate it.
Example
class App extends React.Component {
state = { form: { message: "" } };
handleChangeInput = event => {
const { value, maxLength } = event.target;
const message = value.slice(0, maxLength);
this.setState({
form: {
message
}
});
};
render() {
return (
<input
onChange={this.handleChangeInput}
value={this.state.form.message}
type="text"
className="phone validate"
name="phone"
maxLength="11"
/>
);
}
}
for maxLength to work, type has to be 'text' (most people are probably putting number)
You need to pass maxLength value as a number.
<input
onChange={this.handleChangeInput}
value={this.state.form.message}
type="text"
className="phone validate"
name="phone"
maxLength={11}
/>
inputProps = {{maxLength:6}}
variant="outlined"
Simply do like this in your handleOnChange Function:
handlePasswordChange = (e) => {
if(e.target.value <= 11){
this.setState({
[e.target.name]: e.target.value
});
}
};
For the people who's input type is number, this code will work
handlePhone(object) {
if (object.target.value.length > object.target.maxLength) {
object.target.value = object.target.value.slice(0, object.target.maxLength)
this.setState({ phone: object.target.value });
}
}
<input
placeholder="Phone Number"
onChange={this.handlePhone}
type = "number" maxLength = "10"
/>
<input
id="ZIPCode"
className="form-control"
type="text"
maxLength={10} // this is the important line
></input>
React uses camelCased html attributes, so maxlength would then be maxLength
For anybody using a reactstrap input, like other properties it uses (e.g. colSpan) it needs both camelCase naming and a number passing to it (e.g. maxLength={250}), rather than a string. I have found passing a string will work but React will complain about it.

HTML5 form required attribute. Set custom validation message?

I've got the following HTML form: http://jsfiddle.net/nfgfP/
<form id="form" onsubmit="return(login())">
<input name="username" placeholder="Username" required />
<input name="pass" type="password" placeholder="Password" required/>
<br/>Remember me: <input type="checkbox" name="remember" value="true" /><br/>
<input type="submit" name="submit" value="Log In"/>
Currently when I hit enter when they're both blank, a popup box appears saying "Please fill out this field". How would I change that default message to "This field cannot be left blank"?
The type password field's error message is simply *****. To recreate this give the username a value and hit submit.
Here is some code to display a custom error message:
<input type="text" id="username" required placeholder="Enter Name"
oninvalid="ths.setCustomValidity('Enter User Name Here')"
oninput="setCustomValidity('')"/>
This part is important because it hides the error message when the user inputs new data:
oninput="setCustomValidity('')"
Note: the this keyword is not required for inline event handlers, but you may want to use it anyway for consistency.
Use setCustomValidity:
document.addEventListener("DOMContentLoaded", function() {
var elements = document.getElementsByTagName("INPUT");
for (var i = 0; i < elements.length; i++) {
elements[i].oninvalid = function(e) {
e.target.setCustomValidity("");
if (!e.target.validity.valid) {
e.target.setCustomValidity("This field cannot be left blank");
}
};
elements[i].oninput = function(e) {
e.target.setCustomValidity("");
};
}
})
I changed to vanilla JavaScript from Mootools as suggested by #itpastorn in the comments, but you should be able to work out the Mootools equivalent if necessary.
If setCustomValidity is set to anything other than the empty string it will cause the field to be considered invalid; therefore you must clear it before testing validity, you can't just set it and forget.
As pointed out in #thomasvdb's comment below, you need to clear the custom validity in some event outside of invalid otherwise there may be an extra pass through the oninvalid handler to clear it.
It's very simple to control custom messages with the help of HTML5 event oninvalid
Here is code:
<input id="UserID" type="text" required="required"
oninvalid="this.setCustomValidity('Witinnovation')"
onvalid="this.setCustomValidity('')">
This is most important:
onvalid="this.setCustomValidity('')"
Note: This no longer works in Chrome, not tested in other browsers. See edits below. This answer is being left here for historical reference.
If you feel that the validation string really should not be set by code, you can set you input element's title attribute to read "This field cannot be left blank". (Works in Chrome 10)
title="This field should not be left blank."
See http://jsfiddle.net/kaleb/nfgfP/8/
And in Firefox, you can add this attribute:
x-moz-errormessage="This field should not be left blank."
Edit
This seems to have changed since I originally wrote this answer. Now adding a title does not change the validity message, it just adds an addendum to the message. The fiddle above still applies.
Edit 2
Chrome now does nothing with the title attribute as of Chrome 51. I am not sure in which version this changed.
It's very simple to control custom messages with the help of the HTML5 oninvalid event
Here is the code:
User ID
<input id="UserID" type="text" required
oninvalid="this.setCustomValidity('User ID is a must')">
By setting and unsetting the setCustomValidity in the right time, the validation message will work flawlessly.
<input name="Username" required
oninvalid="this.setCustomValidity('Username cannot be empty.')"
onchange="this.setCustomValidity('')" type="text" />
I used onchange instead of oninput which is more general and occurs when the value is changed in any condition even through JavaScript.
I have made a small library to ease changing and translating the error messages. You can even change the texts by error type which is currently not available using title in Chrome or x-moz-errormessage in Firefox. Go check it out on GitHub, and give feedback.
It's used like:
<input type="email" required data-errormessage-value-missing="Please input something">
There's a demo available at jsFiddle.
Try this one, its better and tested:
function InvalidMsg(textbox) {
if (textbox.value === '') {
textbox.setCustomValidity('Required email address');
} else if (textbox.validity.typeMismatch){
textbox.setCustomValidity('please enter a valid email address');
} else {
textbox.setCustomValidity('');
}
return true;
}
<form id="myform">
<input id="email"
oninvalid="InvalidMsg(this);"
oninput="InvalidMsg(this);"
name="email"
type="email"
required="required" />
<input type="submit" />
</form>
Demo:
http://jsfiddle.net/patelriki13/Sqq8e/
The easiest and cleanest way I've found is to use a data attribute to store your custom error. Test the node for validity and handle the error by using some custom html.
le javascript
if(node.validity.patternMismatch)
{
message = node.dataset.patternError;
}
and some super HTML5
<input type="text" id="city" name="city" data-pattern-error="Please use only letters for your city." pattern="[A-z ']*" required>
The solution for preventing Google Chrome error messages on input each symbol:
<p>Click the 'Submit' button with empty input field and you will see the custom error message. Then put "-" sign in the same input field.</p>
<form method="post" action="#">
<label for="text_number_1">Here you will see browser's error validation message on input:</label><br>
<input id="test_number_1" type="number" min="0" required="true"
oninput="this.setCustomValidity('')"
oninvalid="this.setCustomValidity('This is my custom message.')"/>
<input type="submit"/>
</form>
<form method="post" action="#">
<p></p>
<label for="text_number_1">Here you will see no error messages on input:</label><br>
<input id="test_number_2" type="number" min="0" required="true"
oninput="(function(e){e.setCustomValidity(''); return !e.validity.valid && e.setCustomValidity(' ')})(this)"
oninvalid="this.setCustomValidity('This is my custom message.')"/>
<input type="submit"/>
</form>
I have a simpler vanilla js only solution:
For checkboxes:
document.getElementById("id").oninvalid = function () {
this.setCustomValidity(this.checked ? '' : 'My message');
};
For inputs:
document.getElementById("id").oninvalid = function () {
this.setCustomValidity(this.value ? '' : 'My message');
};
Okay, oninvalid works well but it shows error even if user entered valid data. So I have used below to tackle it, hope it will work for you as well,
oninvalid="this.setCustomValidity('Your custom message.')" onkeyup="setCustomValidity('')"
If your error message is a single one, then try below.
<input oninvalid="this.setCustomValidity('my error message')"
oninput="this.setCustomValidity('')"> <!-- 👈 don't forget it. -->
To handle multiple errors, try below
<input oninput="this.setCustomValidity('')">
<script>
inputElem.addEventListener("invalid", ()=>{
if (inputElem.validity.patternMismatch) {
return inputElem.setCustomValidity('my error message')
}
return inputElem.setCustomValidity('') // default message
})
</script>
Example
You can test valueMissing and valueMissing.
<form>
<input pattern="[^\\/:\x22*?<>|]+"
placeholder="input file name"
oninput="this.setCustomValidity('')"
required
>
<input type="submit">
</form>
<script>
const form = document.querySelector("form")
const inputElem = document.querySelector(`input`)
inputElem.addEventListener("invalid", ()=>{
if (inputElem.validity.patternMismatch) {
return inputElem.setCustomValidity('Illegal Filename Characters \\/:\x22?<>|')
}
return inputElem.setCustomValidity('') // return default message according inputElem.validity.{badInput, customError, tooLong, valueMissing ...}
})
form.onsubmit = () => {
return false
}
</script>
ValidityState
const username= document.querySelector('#username');
const submit=document.querySelector('#submit');
submit.addEventListener('click',()=>{
if(username.validity.typeMismatch){
username.setCustomValidity('Please enter User Name');
}else{
username.setCustomValidity('');
}
if(pass.validity.typeMismatch){
pass.setCustomValidity('Please enter Password');
}else{
pass.setCustomValidity('');
}
})
Adapting Salar's answer to JSX and React, I noticed that React Select doesn't behave just like an <input/> field regarding validation. Apparently, several workarounds are needed to show only the custom message and to keep it from showing at inconvenient times.
I've raised an issue here, if it helps anything. Here is a CodeSandbox with a working example, and the most important code there is reproduced here:
Hello.js
import React, { Component } from "react";
import SelectValid from "./SelectValid";
export default class Hello extends Component {
render() {
return (
<form>
<SelectValid placeholder="this one is optional" />
<SelectValid placeholder="this one is required" required />
<input
required
defaultValue="foo"
onChange={e => e.target.setCustomValidity("")}
onInvalid={e => e.target.setCustomValidity("foo")}
/>
<button>button</button>
</form>
);
}
}
SelectValid.js
import React, { Component } from "react";
import Select from "react-select";
import "react-select/dist/react-select.css";
export default class SelectValid extends Component {
render() {
this.required = !this.props.required
? false
: this.state && this.state.value ? false : true;
let inputProps = undefined;
let onInputChange = undefined;
if (this.props.required) {
inputProps = {
onInvalid: e => e.target.setCustomValidity(this.required ? "foo" : "")
};
onInputChange = value => {
this.selectComponent.input.input.setCustomValidity(
value
? ""
: this.required
? "foo"
: this.selectComponent.props.value ? "" : "foo"
);
return value;
};
}
return (
<Select
onChange={value => {
this.required = !this.props.required ? false : value ? false : true;
let state = this && this.state ? this.state : { value: null };
state.value = value;
this.setState(state);
if (this.props.onChange) {
this.props.onChange();
}
}}
value={this && this.state ? this.state.value : null}
options={[{ label: "yes", value: 1 }, { label: "no", value: 0 }]}
placeholder={this.props.placeholder}
required={this.required}
clearable
searchable
inputProps={inputProps}
ref={input => (this.selectComponent = input)}
onInputChange={onInputChange}
/>
);
}
}
For a totaly custom check logic:
$(document).ready(function() {
$('#form').on('submit', function(e) {
if ($('#customCheck').val() != 'apple') {
$('#customCheck')[0].setCustomValidity('Custom error here! "apple" is the magic word');
$('#customCheck')[0].reportValidity();
e.preventDefault();
}
});
$('#customCheck').on('input', function() {
$('#customCheck')[0].setCustomValidity('');
});
});
input {
display: block;
margin-top: 15px;
}
input[type="text"] {
min-width: 250px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="form">
<input type="text" placeholder="dafault check with 'required' TAG" required/>
<input type="text" placeholder="custom check for word 'apple'" id="customCheck" />
<input type="submit">
</form>
Can be easily handled by just putting 'title' with the field:
<input type="text" id="username" required title="This field can not be empty" />

Categories