How do I validate a number input within a React component - reactjs

In my return statement, I try to check for a valid number or else assign the value 0. This doesn't seem to work, is there a different way of doing this?
return (
<Input
color="teal"
size="regular"
outline={true}
type={question?.type}
name={question?.name}
value={value ?? ''}
placeholder={question?.placeholder ?? ''}
onChange={(e: React.FormEvent<HTMLInputElement>) => {
if (question?.type === 'number' && Number(e.currentTarget.value) < 1) {
e.currentTarget.value = 0;
}
dispatch(
setResponseGeneric({
property: question?.name,
value: e.currentTarget.value,
})
);
}}
></Input>
);

This is because Number('bad input') returns NaN (Not a Number). NaN is a value which is not smaller or greater than 1. You should change your condition so that it handles those scenarios.
if (question?.type === 'number' && (isNaN(e.currentTarget.value) || Number(e.currentTarget.value) < 1)) {
Also something else, besides your question, changing the element value like you do in here e.currentTarget.value = 0; is bad practice since you're changing it imperatively. It's better to make sure you're changing the state so that the value variable becomes 0 (I'm not sure if that already happens in setResponseGeneric).

Related

ReactJS - I implement Binary Search Function, it works only first time

ReactJS - I implement Binary Search Function, it works only first time but after I change the value in the input box, it always return -1 even it has the value in the Array.
Please see the following code:
import React, { useState } from 'react'
import { Container } from 'react-bootstrap'
const binarysearch = () => {
const [ insertValue, setInsertValue ] = useState(0)
var exarr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
// Binary Search
const binarySearch = (arr, val) => {
let start = 0, end = arr.length - 1
while (start <= end) {
let mid = Math.floor((start + end)/2)
console.log(mid)
if (arr[mid] === val) {
return mid
}
if (val < arr[mid]) {
end = mid - 1
} else {
start = mid + 1
}
}
return -1
}
// End Binary Search
return (
<div>
<br />
<hr />
<Container>
<h1>Binary Search</h1>
<h4>Array = {JSON.stringify(exarr)}</h4>
<h4>Search <input type="number" onChange={e => setInsertValue(e.target.value)} /></h4>
<h3>Search {insertValue}, Result in location: {binarySearch(exarr,insertValue)}</h3>
</Container>
<hr />
</div>
)
}
export default binarysearch
First Time Load
After Change Input (Search 10 it should return 10 but -1)
The problem is the fact that e.target.value is always a string, even when the input type attribute is set to "number".
So, when you do arr[mid] === val it will be always false, since this is comparing a number to a string.
You can see this behaviour here.
To fix this, do onChange={e => setInsertValue(Number(e.target.value))}.
Or, alternatively, you can use the non strict equality comparison, which is not really recommended, by replacing the === operator by just ==.
Thank you very much #Mario Vernari
I update the below line to change from string to number, it works properly.
(Insert '+' to insertValue)
From
<h3>Search {insertValue}, Result in location: {binarySearch(exarr,insertValue)}</h3>
To
<h3>Search {insertValue}, Result in location: {binarySearch(exarr, +insertValue)}</h3>

Filter table with select options (check if column is number or null) in React

I am new at React and I am stuck.
I have a table with data from database. I want to filter that table with a select dropdown. I have mulitple "select-fields" that works fine, because the value in the dropdown matches the exact value in database. But now I just want to check if the column value is null or a number.
In my select options I just want three options (see left picture):
All (Show all result. It is working)
Missing number(is null in Database. Not working)
Has number(Not working)
So the value in the table column (see right picture) I want to filter is either a number or null.
Here is my code so far:
const [filteredData, setFilteredData] = useState([]);
//Column in table:
{
Header: () => (<div>TableHead</div>),
accessor: "accessorToDatabase",
Cell: (props) => { return <div>{props?.cell?.value}</div> }
}
// The select dropdown and the table
<Col>
<Label>Select Dropbox</Label>
<Input type="select" onChange={handleChange('id', 'description')}>
<option>All</option>
<option value="false">Missing number</option>
<option value="true">Has number</option>
</Input>
</Col>
<Table columns={columns} data={filteredData} HandleRowData={HandleRowData} />
//The filter functions
const handleChange = name => ({ target: { value } }) => {
filter[name] = (value === 'All') ? null : value
if (checkProperties(filter)) {
var filtered = state
}
else {
var filtered = handleFilter(state, filter)
}
setFilteredData(filtered)
}
const handleFilter = (arr: Object[], filters: Object) => {
const filterKeys = Object.keys(filters)
return arr.filter(eachObj => {
return filterKeys.every(eachKey => {
if (!filters[eachKey] || !filters[eachKey].length) {
return true
}
})
})
}
I have tried with something like this, for looping through all values in the column, but without no success:
state.map(x=>((
x.id> 0 ? x.id : null)))
.map is used to transform one array of values/objects to another array with the same length but with transformed values/objects. What you want to use is .filter, which removes elements from an array but maintain the element structure.
To keep the ones that does not have an id:
array.filter(x => !x.id)
To keep the ones that has an id that is a number:
array.filter(x => !isNaN(x.id))
A simple Array.prototype.filter should do the trick:
//removes all entries with an id of `0 || null || undefined`
state.filter(entry=>!!entry.id)
//removes all entries with an id of `null || undefined` but keeps the 0
state.filter(entry=>!!entry.id || entry.id === 0)
I would not recommend using isNan: as it internally tries to parse strings to check if they are numbers you might end up with some unexpected behaviors. It also goes wild with booleans, null and undefined.
See this link for more info:
https://www.w3schools.com/jsref/jsref_isnan.asp
EDIT
Rereading your question it looks like you want
all items
items with an ID of type number
items that are not numbers
Here is how you could implement that
const [items,setItems]= useState(someItems)
const [filter, setFilter]=useState('all')
function handleChange(e){
setFilter(e.target.value)
}
const filteredItems = items.filter(item=>{
if(filter === 'number')
return typeof items === 'number'
if(filter === 'no-number')
return typeof item !== 'number'
return true
})
return (
<React.Fragment>
<select onChange={handleChange}>
<option value='all'>All</option>
<option value='no-number'>Missing number</option>
<option value="number">Has number</option>
</select>
<Table columns={columns} data={filteredData} HandleRowData={HandleRowData} />
</React.Fragment>
)
Change the elements with the specific library you are using and you are good to go
I would recommend not using NaN, as it tries to parse strings. Instead, you can create an array and use the map function, in combination with the filter function.

How can i make an optional field?

I am making a Checkout form but i dont know how can i make it optional? I'm new with react js and i badly need help because i have defense some time next week and this is the only problem that i am encountering with the revisions that they have said.
Anyway here it is.
const objChecker = (e, id) => {
const hasEmpty = Object.values(orderInfo).some(x => x == '' );
console.log(Object.values(orderInfo), hasEmpty, id)
if(hasEmpty){
window.alert('Please input all fields')
return false
} else {
console.log(e, 'e')
setOrderInfo({ ...orderInfo, payment_id: id })
}
}
<div className='checkout_modal_payment_method_wrap'>
{paymentMethods.length > 0 && paymentMethods.map(method => (
<label htmlFor={`payment_method_${method.id}`} key={method.id} className='checkout_modal_payment_method_item'
style={{display: method.id === 1 && product.category_id === 2 && 'none'}}>
<input type='radio' id={`payment_method_${method.id}`} name='payment_id' value={method.id} onChange={(e) => objChecker(e, method.id)} required checked={payment_id === method.id}/>
<div>
{method.payment_name}
</div>
The only fields that i want to declare as optional is the ADDRESS LINE 2 and TYPE OF EVENT only. The rest will be required
This is the UI

How to pass if condition loop output to a variable in reactjs

I need help to solve this
let someVar
render(
{
this.props.someData.map((items) =>
items.someotherData.map((item) =>
(item.data1 > 5 && item.data2 == "more") ? classNames({ "classname1": true })
: (item.data1 > 5 && item.data2 == "less") ? classNames({ "classname2": true })
: classNames({ "classname3": true })
))
}
<div className = { someVar } ></div>
)
I need my output of if loop to be pass to the variable
I tried many method. Nothing worked. Please give the solution
render() {
let someVar
this.props.someData.forEach(items =>
items.someotherData.forEach(item =>
item.data1 > 5 && item.data2 == 'more'
? someVar = 'classname1'
: item.data1 > 5 && item.data2 == 'less'
? someVar = 'classname2'
: someVar = 'classname3'
)
)
return <div className={someVar}></div>
}
I didn't really get what you were trying to do. Are you calling some function with the class names or something? Here is my best try to solve your problem though.
First we create the variable,
Then we do data processing. You shouldn't use map but instead the forEach if you are not returning anything. You are also overwriting the variable for each item (is this preferred behaviour?).
Then we actually return the React part of the code. Render function always needs to return JSX or null. Inside JSX we can use the someVar in the className. The final value of className needs to be a string. That's why we are putting strings to the someVar.

How to prevent a user pasting specific special characters (only allowed characters include (_ - .) in a form using jsx

I also want to limit the first character to just a number or a letter.
This is what I have so far to prevent the user from typing in special characters:
validate(event) {
const keycode = event.keyCode || event.which || event.type === 'paste';
const key = String.fromCharCode(keycode);
const pattern = new RegExp('^[a-zA-Z0-9\\_\\.\\-]$');
return pattern.test(key) ? key : event.preventDefault();
}
const validateMyField = (currentFieldValue, props) => {
if (currentFieldValue.match(/^[a-zA-Z0-9\\_\\.\\-]+$/)) {
return true;
}
return false;
};
const templateNameValidator = createValidator(
validateMyField,
'You are attempting to paste with characters that are not allowed. Please remove characters and try again. (special characters can only include "_","-",".")'
);
<Field
className="usaa-input"
component={Textarea}
label="Template Name"
name="name"
maxLength={128}
minRows={1}
placeholder="Enter Template Name..."
validate={composeValidators(required, templateNameValidator)}
onKeyPress={this.validate}
/>
It might be easier to use a controlled input. This is where we get and set the value to and from the state.
this.state = {inputValue: ""}
...
validateBeforeInput(e){
if(matches the chars we want){
this.setState({inputValue: e.target.value})
}
}
...
<input
value={this.state.inputValue}
onChange{validateBeforeInput} // where the magic happens
/>

Resources