React/JavaScript - Validate two or more inputs - javascript

Is it possible to validate two or more inputs in the same file ? As I am trying to create a second validator for another input. I have one validator for a number input -
function FormVal() {
const [phone, setPhone] = React.useState<string>();
const [errors, setErrors] = React.useState<{ phone: string }>();
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const {
target: { value }
} = event;
setErrors({ phone: '' });
setPhone(value);
let reg = new RegExp(/^\d*$/).test(value);
if (!reg) {
setErrors({ phone: 'Only numbers' });
}
};
}
I would like to create second input like email or text but I don't want to create a new file and I was wondering how can I add another validator there.

Instead of using the above-mentioned approach, What you can do is create a schema to validate the inputs. There are many great libraries for this.
In a large project writing a validator for each type of input can be a complex task. You can use fastest-validator which is the fastest data validation library for javascript.

Related

Filtering Multiple input on a single json

I have a json file with object
obj= [{fname:"abhi",age:5,class:"ten",lanme:"kumar"
},{fname:"abhi",age:5,class:"ten",lanme:"kumar"
},{fname:"abhi",age:5,class:"ten",lanme:"kumar"
},{fname:"abhi",age:5,class:"ten",lanme:"kumar"
}]
which I display in the following table
enter image description here
i am trying to build a filter for the above table but I am not able to filter it out
Can anyone please help me on this
Note: Second Row each Column is a Filter for only that column that is Class searches only class column not everything
And that search should populate in that table
Can anyone please help I am stuck here from ages on this specially with useState Hook
Stack Used : React & Javascript no third party library
Currently my filter is something like this
const [value, setValue] = useState({
lastname: '',
class: '',
firstname: '',
});
const handleSubmit = e => {
const searchValue = {
...value,
[e.target.name]: e.target.value
};
setValue(searchValue);
setCopyList(
copyList.filter(item => item[e.target.name].includes(e.target.value))
);
};
currently what is happening is as soon as I search on each individual column it refreshes the search on the present values
first You make a generic function and then implement every input text
field. This solution is especially in react js and js.
const searchByName = (name) => {
if (name !== "") {
console.log(name);
const res = data.filter((sd) => {
return (
sd.firstName.toString().toLowerCase().includes(search) ||
sd.email.toString().toLowerCase().includes(search)
);
});
console.log(res);
setData(res);
} else {
setData(dataFilter);
}
};

How do you set multiple properties to be returned in Javascript-React?

I am trying to build a search box. When you type in it, it automatically filters my App.js file (Cards of robots).
render() {
const filteredRobots = this.state.robots.filter(robots => {
return robots.name.toLowerCase().includes(this.state.searchfield.toLowerCase())
})
return(
<div className='tc'>
<h1>RoboFriends</h1>
<SearchBox searchChange={this.onSearchChange}/>
<CardList robots={filteredRobots}/>
</div>
)
}
I have a separate, robots.js file in which I list the properties of the robots:
export const robots = [
{
id: 1,
name: 'Leanne Graham',
username: 'Bret',
email: 'Sincere#april.biz'
},
My filter method works, when I only put a single property in it. In the code above, I am illustrating it when it is filtered by name. I would like to include the "email" property as well, so that when I type in the search field, it also filters by the email and not just the name.
Thanks in advance, this is my first post, sorry for not being clear, I recently started learning.
You can combine the objects fields into a single string and use it instead of using the name
const filteredRobots = this.state.robots.filter(robot => {
return Object.values(robot).join(" ").toLowerCase().includes(this.state.searchfield.toLowerCase())
})
Now, all the robot fields (name, username, email, id) are considered in your search function.
filter method passes the array items directly.
const searchedString = this.state.searchfield.toLowerCase()
const filteredRobots = robots.filter(robotItem => robotItem.name.toLowerCase().includes(searchedString) || robotItem.username.toLowerCase().includes(searchedString) )
more about the filter method in mdn docs

conditional validation with yup

I have 3 fields in a form, the "type" field is select and from that list, some items enable or disable the "out" field, if is enable I need the "out" field to be less than the "in" field and vice-versa, but if the "out" field is disabled I don't need that validation, I was trying something with .when, but is not working, any ideas on how to do this?
const [disableOutCounterField, setDisableOutCounterField] = useState(false);
const schema = yup.object().shape({
type: yup.string().required(requiredMessage),
in: yup
.number(numberMessage)
.required(requiredMessage)
.integer(integerMessage)
.min(1, positiveMessage)
.typeError(numberMessage)
.when("out", {
is: !disableOutCounterField,
then: yup.number().moreThan(yup.ref("out"), moreThanMessage),
message: moreThanMessage,
}),
out: yup
.number(numberMessage)
.integer(integerMessage)
.typeError(numberMessage)
.lessThan(yup.ref("in"), lessThanMessage),
});
The construct:
.when("out", {
is: !disableOutCounterField,
compares the out value with !disableOutCounterField, and if they are equal, the then rule is applied. But quite likely they are never the same.
The check that is needed here is just the value of !disableOutCounterField by itself, for any value of out. This can be done using an expression:
.when("out", {
is: value => !disableOutCounterField,
In words: for every out value, return !disableOutCounterField, and if it returns true, apply the then part.
An alternative I found for this is to regenerate the object validationSchema from inside a useEffect.
This has the benefit of using useState without having them mapped to specific form fields ahead of time, such as if you set something conditionally from the database and don't want to set it as a hidden field somewhere.
const validationPiece = yup.object({
amount: yup
.number()
.typeError('Please enter an amount')
.required('Please enter an amount')
});
const [validationSchema, setValidaitonSchema] = useState(yup.object({}));
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm({
resolver: yupResolver(validationSchema),
});
useEffect(() => {
if (needNewPartOfForm) {
const validationSchemaDict = {};
if (needNewPartOfForm.xyz) {
validationSchemaDict['xyz'] = validationPiece; // does this need a cloneDeep?
}
if (needNewPartOfForm.abc) {
validationSchemaDict['abc'] = validationPiece;
}
setValidaitonSchema(yup.object(validationSchemaDict));
}
}, [clientDocs, clientId, reset, teamId]);

how to update array of objects when input is changed

I have an array of objects
const data= [
{ id:1,name:"apple", city:"ban" },
{ id:2,name:"mango", city:"hyd" }
]
And I have two input fields when the user fills. if !null then I need to add an object to "data" {id:2,name:"apple",city:"nel"} and the id of the 2 in the data object should be 3 and if again the user makes it to null ie deleted the value from the input field need to remove this {id:2,name:"apple",city:"nel"} and make the id from 3 to 2. similarly of the user gives 2 inputs i need to add 2times {id:2,name:"apple",city:"nel"},{id:3,name:"apple",city:"nel"} and make the id of 2 to 4. similarly if the user deletes eaither/or deletes both or single data from the input i need to add or remove the data array accordingly can anyone please help me with this in react with hooks
You can track the form values with a single useState() hook.
You can use both input onChange event handlers, and form onSubmit event handler to build a component that behaves like you want.
The following is an example React component with hooks you can take as a starting point to manage your state. Please take it as a template and tweak it as needed to fulfill your actual requirement.
const storedData = [
{ id: 1, name: 'apple', city: 'ban' },
{ id: 2, name: 'mango', city: 'hyd' },
]
let nextId = 3
const MyFormComponent = () => {
const initialFormData = { name: '', city: '' }
const [formData, setFormData] = useState(initialFormData)
const clearFormData = () => {
setFormData(initialFormData)
}
const handleOnInputChange = (event) => {
const { value, name } = event.target
// merge previous formData with the new value from input
setFormData({
...formData,
[name]: value,
})
}
const handleOnSubmit = (event) => {
// prevent HTML form default handler (navigation, etc.)
event.preventDefault()
const { name, city } = formData
// OPTIONAL: handle form data validations
if (name === '') {
// no "name" provided
alert('Must specify a name!')
return
}
// input1 "name" and input2 "city" are available in formData
// TODO handle the form data and implement your application logic / update storedData / etc.
// TODO a rough example below, please tweak it to match your requirements
const existingEntryByIndex = storedData.findIndex(
({ name }) => formData.name === name
)
if (existingEntryByIndex >= 0 && formData.city === '') {
// name exists and city value is empty => delete this entry
// NOTE: city value can't be null, because it will be always a string. Maybe, you can use "null" string though.
storedData.splice(existingEntryByIndex, 1)
} else {
// name exists and city not empty, or name is new => add a new city
storedData.push({ id: nextId, name, city })
nextId++
}
// --- end of rough example ---
// OPTIONAL: clear the form values ->
clearFormData()
}
return (
<div className={'my-form-container'}>
<form onSubmit={handleOnSubmit}>
<input
type="text"
name="name"
value={formData.name}
onChange={handleOnInputChange}
/>
<input
type="text"
name="city"
value={formData.city}
onChange={handleOnInputChange}
/>
</form>
</div>
)
For further reference, you can check the React docs to learn about more techniques and ways to handle form inputs, and events.

Yup conditional validation based on a a non field value

I am trying to create a yup schema where based on a variables value the schema changes slightly. In my case depending on the value of prop myCondition I need to make a field as required. I would like to know if there is any better way I can achieve the same using Yup. Here's my current code structure that works:
// config.js
const COMMON_SCHEMA = {
str1: yup
.string()
.nullable()
.required('Please input str1'),
str3: yup
.string()
.nullable()
};
const VALIDATION_SCHEMA_1 = yup.object().shape({
...COMMON_SCHEMA,
str2: yup.string().nullable(),
});
const VALIDATION_SCHEMA_2 = yup.object().shape({
...COMMON_SCHEMA,
str2: yup
.string()
.nullable()
.required('Please input str2'),
});
const SCHEMAS = {
VALIDATION_SCHEMA_1,
VALIDATION_SCHEMA_2
}
export default SCHEMAS;
the following is how I conditionally choose different schemas:
// app.js
import SCHEMAS from './config';
...
<Formik
validationSchema={
this.props.myCondition === true
? SCHEMAS.VALIDATION_SCHEMA_1
: SCHEMAS.VALIDATION_SCHEMA_2
}
>
...
</Formik>
I feel like I can achieve whatever I am doing above in an easier way with yup. One of the approaches I tried was to pass in the prop myCondition into config file and work with it's value by using yup.when() but when only works if the value you want to use is also a part of the form so I couldn't achieve the same.
This can be achieved by the following way:
You can wrap your schema in a function and pass your conditonal prop:
const wrapperSchema = (condition) =>
Yup.object().shape({
...COMMON_SCHEMA,
str2: yup.string()
.when([], {
is: () => condition === true,
then: yup.string().nullable(),
otherwise: yup.string().nullable().required('Please input str2'),
}),
});
Please note that first param of when is a required param, you can also pass e.g. ["title", "name"] where title and name can be your field values, and you can retrieve and use them in is callback, in the same order, if you have to.
You can conditionally add validation directly in the validationSchema, like this: https://stackoverflow.com/a/56216753/8826314
Edited to add, you can include your value in the initial form, so that you can do the when check against that field. For example:
<Formik
initialValues={
...,
str2
}
validationSchema={
...,
str2: yup.object().when('str2', {
is: str2 => condition check that returns boolean,
then: Yup.string().nullable(),
otherwise: Yup.string().nullable().required('Please input str2')
})
}
>
...
</Formik>

Categories

Resources