only allowing numbers upto certain length in material ui - javascript

We need user to enter only numbers and it should have a maximum length of say 3.
How can we accomplish this in material ui ?
<TextField
id="score"
label="score"
className={classes.textField}
name="totalScore"
margin="normal"
defaultValue={score}
/>
We want only numeric values here

Try this...
<TextField
id="score"
label="score"
name="totalScore"
style={style.filedStyle}
inputProps={{ min: 3, max: 3}}
/>

Actually this is the way it works, you have input type as number. so, you can apply max attribute but it will validate not limit the input numbers, Checkout this thread.
The workaround is to apply oninput and count the length. like this
onInput={(e)=>{
e.target.value = Math.max(0, parseInt(e.target.value) ).toString().slice(0,3)
So your textinput would look like
<TextField type="number"
className="text-field-amount"
onInput={(e)=>{
e.target.value = Math.max(0, parseInt(e.target.value) ).toString().slice(0,2)
}}
min={0}
/>
Demo

Use controlled input, and update state only if the input is number.
ex:
state will be like this
this.state={
score: 0
}
create a function to handle change in text field.
handleChange(e){
//update state here with value from TextField.
}
and your textfield will look like this.
<TextField
id="score"
label="score"
className={classes.textField}
name="totalScore"
margin="normal"
value={this.state.score}
onChange={this.handleChange.bind(this)}
/>

<TextField
id="score"
label="score"
className={classes.textField}
name="totalScore"
margin="normal"
defaultValue={score}
/>
you can do this with Jquery
$('#score').keypress(function(e){
var code = (e.which) ? e.which : e.keyCode;
if($('#' + e.target.id).val().length > 2)
e.preventDefault();
if (code > 31 && (code < 48 || code > 57)) {
e.preventDefault();
}
});

<TextField
id="number"
placeholder="Enter Number"
type="number"
value={state.count}
onChange={(event) => {
const regex = /^([0-9]){minLength,maxLength}$/;
if (event.target.value === '' || regex.test(event.target.value)) {
setState({ ...state, count: event.target.value });
}
}}
variant="outlined" />

number + length restriction
<TextField
value={phone}
onChange={event => setPhone(event.target.value)}
variant="outlined"
placeholder={'Phone number'}
type={'number'}
onInput={(e)=>{e.target.value = Math.max(0, parseInt(e.target.value)).toString().slice(0,10)}}
min={0}
/>

Related

how to validate user inputs in react using setState hook

I have a form. In the form I getting brandName, supplierName, and date of expiry from the user.
I am usinf TextField from mui library and submit button.
I want to disable submit button on empty form fields and enable it when user filled all the inputs
here is my code for declaring useStates
const[brandName, setBrandName] = useState("");
const[supplierName, setSupplierName] = useState("");
const[expiryDate, setExpiryDate] = useState(null);
const[brandNameError, setBrandNameError] = useState(false);
const[supplierNameError, setSupplierNameError] = useState(false);
const[expiryDateError, setExpiryDateError] = useState(false);
const[submitButton, setSubmitButton] = useState(true);
and here is all function which i used to validate my inputs
// checking brandName Error
const brandNameValidateOnBlur = ()=>{
if(brandName === ""){
setBrandNameError(true);
}
}
// checking supplier name error
const supplierNameValidateOnBlur = ()=>{
if(supplierName === ""){
setSupplierNameError(true);
}
}
// checking expiry date
const expiryDateValidateOnBlur = ()=>{
if(expiryDate === ""){
setExpiryDateError(true);
}
}
// now checking all inputs again if all inputs are good then
// button should be enabled
const checkAllInputs = ()=>{
if(brandName !== "" && supplierName !== "" && expiryDate !== ""){
setSubmitButton(false);
}else{
setSubmitButton(true);
}
}
and here is the rest of code
<TextField fullWidth id="productName" label="Product Name"
value={brandName.toLowerCase()} variant="outlined"
onChange={(data)=>{setBrandName(data.target.value.toUpperCase());checkAllInputs()}}
onBlur={brandNameValidateOnBlur}
onFocus={()=>setBrandNameError(false)}
error={brandNameError}
helperText = {brandNameError ? "Enter Brand Name" : ""}
/>
<TextField id="supplierName"
label="Supplier Name"
value={supplierName.toLowerCase()} variant="outlined"
onBlur={supplierNameValidateOnBlur}
onFocus={()=>setSupplierNameError(false)}
error={supplierNameError}
helperText={supplierNameError ? "Enter Supplier Name " : ""}
onChange={(data)=>{setSupplierName(data.target.value.toUpperCase());checkAllInputs()}} />
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DesktopDatePicker
label="Date Expiry"
inputFormat="MM/DD/YYYY"
value={expiryDate}
onBlur={expiryDateValidateOnBlur}
onFocus={()=>setExpiryDateError(false)}
error={expiryDateError}
helperText={expiryDateError ? "Enter Expiry Date ": ""}
onChange={(selectedDate)=>
{setExpiryDate(selectedDate.format("MM/DD/YYYY"));checkAllInputs()}}
renderInput={(params) => <TextField {...params} />}
/>
</LocalizationProvider>
<Button type='button' variant='contained' id="submitButton" disabled={submitButton}
style={{backgroundColor:'orangered'}} onClick={addData}>Add Data</Button>
now problem is when i enter a single word my useState is updated but my checkAllInputs not working as i want to be like if i enter a word my checkAllInputs method runs before setting of state as i enter second entry then it works like I want to be so i did not know what i am doing wrong
I TRY useEffect hook like that
useEffect(()=>{
checkAllInputs();
},[brandName, supplierName, expiryDate]);
its working fine as i accepted but I read that it should be a expensive to use useEffect
and an other approach which i use
const checkAllInputsWithDom = ()=>{
let brandNameEntry = document.getElementById("brandName").value;
let supplierNameEntry = document.getElementById("supplierName").value;
let expiryDateEntry = document.getElementById("expiryDate").value;
if(brandNameEntry !=="" && supplierNameEntry !== "" && expiryDateEntry !== ""){
setSubmitButton(false);
}else{
setSubmitButton(true);
}
}
it is working out of box but I thing in react this is against react principles to direct manipulate
dome elements can I do it with out using useeffect hook like only with my metohd and one more thing
this did not set expiryDate error in date field
As long as you're keeping the input values in state, you don't need another variable storing the button state as well. You can calculate it at render time. (Read more about avoiding redundant state here.)
You could do something like this:
const Component = () => {
const[brandName, setBrandName] = useState("");
const[supplierName, setSupplierName] = useState("");
const[expiryDate, setExpiryDate] = useState("");
const disabled = brandName.length === 0 && supplierName.length === 0 && expiryDate.length === 0
return (
<>
<input value={brandName} onChange={(e) => setBrandName(e.target.value)}/>
<input value={supplierName} onChange={(e) => setSupplierName(e.target.value)}/>
<input value={expiryDate} onChange={(e) => setExpiryDate(e.target.value)}/>
<button disabled={disabled}>Button</button>
</>
)
}
here is the link for codesandbox I have a suggestion for you to refactor this 6 use States with just one useState as an object having all the values like the following:
const initialValues = {
brandName: "",
supplierName: "",
expiryDate: "",
brandNameError: "",
supplierNameError: "",
expiryDateError: ""
};
and then update it with a generic handleInputChange like below:
const handleInputChange = (e) => {
//const name = e.target.name
//const value = e.target.value
const { name, value } = e.target;
setValues({
...values,
[name]: value
});
let isEmpty = Object.values(values).some((x) => x === "");
console.log(isEmpty);
setIsDisabled(isEmpty);
};
FOR YOUR SOLUTION
You will have to just check all the values and just create a boolean with isDisabled so when all of those values are empty then it will only set to false.
I have created a code snippet for you, it needs some improvement but it will serve your purpose. Link already at the top and here as well
as suggested by Eduardo Motta de Moraes
I used this for making my button enabled after all inputs validate
const disabled= brandName.length === 0 || supplierName.length === 0 || expiryDate.length === 0;
this solve my problem
thanks for Eduardo Motta de Moraes for this

Return the default value in the TextField

There are several filters on my site (by date, duration, and so on). Accordingly, from a large amount of data, the user can find what he needs
There is also a "reset all filters" button that resets all filters and returns the full list of products.
However, with one of the filters, I ran into a problem: in this filter, I use a TextField from the mui. And the problem is that the values ​​themselves, by which the desired products are filtered, are discarded, and what the user entered in the field remains unchanged.
I will give an example: The user filters only by this field. Having received any result, he wants to return to the original list and presses the "reset all filters" button. All filters are reset and the original list is returned, but the data entered in the field remains, that is, the field itself is not cleared.
Help solve the problem
const MAX_DURATION = 9999999
export default function FilterDuration() {
const [minDuration, setMinDuration] = useState(0);
const [maxDuration, setMaxDuration] = useState(MAX_DURATION);
useEffect(() => {
updatedFilters.durationRange = { min: minDuration, max: maxDuration }
setFilters(updatedFilters)
if (maxDuration === 0) {
setMaxDuration(MAX_DURATION)
}
}, [minDuration, maxDuration])
return (
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<div style={{ width: "120px" }}>
<TextField
onInput={(e) => {
const newValue = Number(e.target.value)
if (newValue )
setMinDuration(newValue)
}} />
</div>
</div>
);
}
Add a value prop to your TextField which has the minDuration like this:
<TextField
type='number'
size="small"
margin="dense"
label="From"
value={minDuration}
onInput={(e) => {
e.target.value = Math.max(0, parseInt(e.target.value)).toString().slice(0,7)
const newValue = Number(e.target.value)
if (newValue <= maxDuration && newValue >= 0 && newValue <= MAX_DURATION)
setMinDuration(newValue)
}} />
You want the value of the TextField to be managed by the state of your component. Add a value attribute and set it to the current value of minDuration:
<TextField
...
value={minDuration}
/>

Input Masking in Javascript

I have an input where users are going to type identification numbers and I would like to mask that input so that it always has this format : XX-XXXXXXXX-X
The X's can only be numbers and the dashes need to be always in those positions.
Here is what I got so far:
import React from "react";
import { Inertia } from "#inertiajs/inertia";
import {useForm, usePage} from "#inertiajs/inertia-react";
import ErrorForm from "./ErrorForm"
function Login() {
const{data , setData , processing ,reset} = useForm({
cuit: '',
password: ''
})
const errors = usePage().props.errors
function submit(e){
e.preventDefault()
Inertia.post(route('login'),data,{
onError:() => reset('password')
})
}
function handleChange(e){
if(e.target.value.length === 11){
e.target.value = [e.target.value.slice(0,11),'-'].join('')
}else if(e.target.value.length >= 2){
if(!e.target.value.includes('-')){
e.target.value = [e.target.value.slice(0,2),'-',e.target.value.slice(2)].join('')
}
}
setData('cuit',e.target.value)
}
function handleKeyDown(e){
if(e.key === "0" || e.key === "1" || e.key === "2" || e.key === "3" || e.key === "4" || e.key === "5" || e.key === "6" || e.key === "7" || e.key === "8" || e.key === "9"){
handleChange(e)
}
}
return(
<div className="ContenedorLogin">
<form onSubmit={submit}>
<input
name="cuit"
type="text"
placeholder="C.U.I.T."
className="input"
onKeyDown={handleKeyDown}
maxLength="13"
/>
{errors.cuit &&
<ErrorForm
content={errors.cuit}
/>
}
<input
name="password"
type="Password"
placeholder="Contraseña"
className="input"
value={data.password}
onChange={e => setData('password',e.target.value)}
/>
<button className="btn-consejo" type="submit" disabled={processing}>INGRESAR</button>
</form>
</div>
)
}
export default Login
Basically I'm capturing a keyDown event, then changing the input only if the user typed a number and finally in the handleChange function I try to mask and set the value.
It kind of work but not for all cases, for example if I'm in the middle of typing and I already have the first dash and I add a number before the first dash its going to allow it leaving me with something like this : XXXX-XXXXX
I imagine I can achieve the result using regular expressions or something like that but I'm not familiar at all with them
Thanks in advance!
It would work if you bind event on whole input value instead of each key press.
Here, instead of using event "onKeyDown", use "onChange". Also You can use html pattern for accepting number only.
<input
name="cuit"
type="number"
pattern="[0-9\/]*"
placeholder="C.U.I.T."
className="input"
onChange={handleChange} // calling handleChange on input change directly
maxLength="13"
/>
You already have working handleChange() function, which will work perfectly.
Instead of using JS to do this use the in-build HTML form validation.
Add a required attribute and a regex pattern to the input. The form won't submit until the input has been validated. And you'll also get little tool-tips to explain what the issue is if you try to submit and the input isn't validated.
In this case the regex reads:
^ - start of the value
[0-9]{2}- two numbers followed by a dash
[0-9]{8}- eight numbers followed by a dash
[0-9] - one number
$ - end of the value
const { useState } = React;
function Example() {
const [input, setInput] = useState('');
function handleSubmit(e) {
e.preventDefault();
console.log(`Submitted: ${input}`);
}
function handleChange(e) {
setInput(e.target.value);
}
return (
<form onSubmit={handleSubmit}>
<input
onChange={handleChange}
placeholder="dd-dddddddd-d"
pattern="^[0-9]{2}-[0-9]{8}-[0-9]$"
value={input}
required
/>
<button type="submit">Submit</button>
</form>
);
}
ReactDOM.render(
<Example />,
document.getElementById('react')
);
input, button { font-size: 1.2em; }
input { padding: 0.3em; }
input:invalid { border: 1px solid red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

I need to subtract the count and update the remaining count

I am using TextField that field data I am adding into the table that works fine what my task is I have one field called Total no of count their I am storing my data count so whenever I add data into the table it will be based on the count, mean like example if I have count 3 then I am able to use count max 3 or if I want to divide that count with a different name that also works only max count I used whatever present in Total no of count or after dividing count with a user name I need to update remaining count in that field or whatever count is present after added into a table showing remaining count when I use all count in one time or add it to the table that works fine mean Total no of count get subtracted with table data count and remain 0 but when I divide that count into 2 or 3 names field mean by 1 by 1 then it will not work properly mean count not get subtracted properly
In this method, I am subtracting and setting the remaining count
const totalRemainingCount =
totalUsers -
Number(
AssignSearchesForm.values.countAssigned ||
teamdata?.map((data) => data.countAssigned)
);
export default function App() {
const [teamdata, setTeamData] = React.useState([]);
const AssignSearchesForm = useFormik({
initialValues: {
selectName: "",
selectAge: "",
location: "",
countAssigned: ""
},
validationSchema,
onSubmit: (values, formikHelper) => {
setTeamData([values, ...teamdata]);
formikHelper.resetForm();
}
});
let filteredArray = nameList.filter(
(e) => !teamdata.some((data) => data.selectName === e.selectName)
);
const handleChange = (e) => {
const selectedName = e.target.value;
const name = nameList.find((data) => data.selectName === selectedName);
const newOptions = Object.values(name).reduce((optionList, key) => {
optionList.push({ value: key, label: key });
return optionList;
}, []);
AssignSearchesForm.setFieldValue("selectName", selectedName);
AssignSearchesForm.setFieldValue("selectAge", newOptions[1]?.value || "");
AssignSearchesForm.setFieldValue("location", newOptions[2]?.value || "");
};
const totalUsers = 3;
const totalRemainingCount =
totalUsers -
Number(
AssignSearchesForm.values.countAssigned ||
teamdata?.map((data) => data.countAssigned)
);
return (
<div className="App">
<Card color="primary" variant="outlined">
<CardHeader
title={
<Typography variant="subtitle1">
Total no of count ={" "}
{totalRemainingCount <= 0 ? 0 : totalRemainingCount}
</Typography>
}
/>
<Divider />
<CardContent>
<Grid container direction="row" spacing={1}>
<Grid item xs={4}>
<TextField
sx={{ minWidth: 185 }}
select
id="outlined-basic"
label="Select Name"
name="selectName"
size="small"
onChange={handleChange}
value={AssignSearchesForm.values.selectName}
error={
AssignSearchesForm.errors.selectName &&
AssignSearchesForm.touched.selectName
}
helperText={
AssignSearchesForm.touched.selectName &&
AssignSearchesForm.errors.selectName
}
>
{filteredArray?.map((option) => (
<MenuItem key={option.selectName} value={option.selectName}>
{option.selectName}
</MenuItem>
))}
</TextField>
</Grid>
<Grid item xs={4}>
<TextField
id="outlined-basic"
label="location"
name="location"
size="small"
{...AssignSearchesForm.getFieldProps("location")}
error={
AssignSearchesForm.touched.location &&
AssignSearchesForm.errors.location
}
helperText={
AssignSearchesForm.touched.location &&
AssignSearchesForm.errors.location
}
/>
</Grid>
<Grid item xs={4}>
<TextField
id="outlined-basic"
label="Select Age"
name="selectAge"
size="small"
{...AssignSearchesForm.getFieldProps("selectAge")}
error={
AssignSearchesForm.errors.selectAge &&
AssignSearchesForm.touched.selectAge
}
helperText={
AssignSearchesForm.touched.selectAge &&
AssignSearchesForm.errors.selectAge
}
/>
</Grid>
<Grid item xs={4}>
<TextField
id="outlined-basic"
label="Count Assign"
name="countAssigned"
size="small"
type="number"
{...AssignSearchesForm.getFieldProps("countAssigned")}
error={
AssignSearchesForm.errors.countAssigned &&
AssignSearchesForm.touched.countAssigned
}
helperText={
AssignSearchesForm.touched.countAssigned &&
AssignSearchesForm.errors.countAssigned
}
/>
</Grid>
<Grid item xs={4}>
<Button
onClick={() => {
AssignSearchesForm.handleSubmit();
}}
variant="contained"
>
Add
</Button>
</Grid>
</Grid>
</CardContent>
</Card>
<Table teamdata={teamdata} />
</div>
);
}
CodeSandBox Link
You need to update your logic for the way you are calculating the count:
const totalRemainingCount =
totalUsers -
(parseInt(
AssignSearchesForm.values.countAssigned
? AssignSearchesForm.values.countAssigned
: 0,
10
) + teamdata?.reduce((partialSum, a) => partialSum + a.countAssigned, 0));
You were getting NaN because the data you were trying to use for subtraction was not the number. Here, I am doing the sum of countAssigned in the table and adding it with the form data that will allow you to get the right value.
Here is an example:https://codesandbox.io/s/preset-ranges-antd-4-19-2-forked-kczd1y?file=/App.js:1838-2095
What I have understood so far is that the Total count is not setting properly. If this is the case then you need to set state of count when you click add button, so that it stores the countAssigned value. Also using the max property in TextField to limit the count to remaining value.
I have edited your codesandbox example.

validation fails on submit

The code should validate that the input fields dont contain a number and only letters and also both fields arent blank. Currently it works with detecting if they aren't blank but it only detects a number in 'firstname' - I have managed to get one or the other working but never both at the same time. Help!!
Also, If the validation fails the joke shouldn't be returned (the button onclick provides the joke by using the first and last name and sending it to an api to retrieve the joke).
function validateForm() {
var firstname = document.getElementsByName("firstname")[0].value;
var lastname = document.getElementsByName("lastname")[0].value;
var input = document.getElementsByName("firstname" && "lastname");
if (firstname == "" && lastname == "") {
alert("Please enter atleast one name");
}
else if (!(/^[a-zA-Z]+$/.test(firstname || lastname))) {
alert("'Only alphabets allowed'");
}
}
return (
<div className="jokeForm" >
<form name="searchForm" >
<input type="text" name="firstname" placeholder="First name" value={firstname} onChange={(e) => setFN(e.target.value)} />
<input type="text" name="lastname" placeholder="Last name" value={lastname} onChange={(e) => setLN(e.target.value)} />
</form>
<button onClick={() => validateForm(newJoke(firstname, lastname))}>click here for a personalised chuckle</button>
<h3>{joke}</h3>
</div >
)
}
Use + to add both strings together. And do test with Regex. eg.
var firstname="j";
var lastname="k1";
if (!(/^[a-zA-Z]+$/.test(firstname + lastname))) {
alert("Only alphabets allowed!");
}

Categories