How to validate input fields in react? - javascript

I am using react-hook-form for the validation of my form in react.
What I am doing
I have one select dropdown, which has some numbers as a dropdown.
On change of select dropdown I am creating the input field, if 2 is selected then 2 input field, initially one is there by default.
Now when I select 2 or 3 options and create 2-3 input fields, on click of a button it is only taking last field validation as well as giving me the last field value only.
In react-hook-form we use ref to hold the value of particular input and for validation as well.
But here it is only validating the last one only, I do not know what I am missing.
This is what I am doing.
<div className="row">
{[...Array(inputHolder).keys()].map((li, index) => (
<div className="col-12 col-sm-12 col-md-8 col-lg-4 col-xl-4">
<div className="form-group">
<input
type="text"
name="name"
id={'name' + index}
className="form-control"
placeholder="F Name"
ref={register({required: 'F name is required'})}
/>
<label className="common_label_form" htmlFor={'name' + index}>
F Name
</label>
{errors.name && (
<div>
<span className="text-danger">{errors.name.message}</span>
</div>
)}
</div>
</div>
))}
</div>;
This my code sandbox
I need to make my refs dynamic but I don't know how can I achieve that.
I want to have data like [{ name: 'name1' }, { name: 'name2' }], that's why I have been stuck, once I will get data then I can push it inside array.

When using form, any input elements (input, select...) inside it is identified via a name attribute, not id as you may think.
Solution 1:
map(_, index) => (
<input
name={`name[${index}]`}
ref={register}
/>
)
When you log the submit data, here is what it looks like
{
"name": ["1", "2", "3"]
}
Error displaying:
{errors.name && errors.name[index] && (
<div>
{errors.name[index].message}
</div>
)}
Solution 2:
map(_, index) => (
<input
name={`data[${index}].name`}
ref={register}
/>
)
Output
{
"data": [
{ "name": "1" },
{ "name": "2" },
{ "name": "3" }
]
}
Error displaying
{errors.data && errors.data[index] && errors.data[index].name && (
<div>
{errors.data[index].name.message}
</div>
)}
Solution 3:
map(_, index) => (
<input
name={`name_${index}`}
ref={register}
/>
)
Output:
{
"name_0": "1",
"name_1": "2",
"name_2": "3"
}
Error displaying:
{errors["name_" + index] && (
<div>
{errors["name_" + index].message}
</div>
)}
Live Demo

I think you shoud simply change the input name li ke this
...
<input
type="text"
name={'name' + index} // you should change this
id={'name' + index}
className="form-control"
placeholder="F Name"
ref={register({required: 'F name is required'})}
/>
...

Related

React - JS variables not updating properly on click

I made this button handle function, when clicked it will check the entered character against the stored "hangman" word.
If the letter exists in the string it shows its correct and increase
"guesses"
If it isn't present it will increase both "guesses" and "incorrect"List item
If the letter has already been tried or contains "" / " " it will do
nothing
However the functionality is acting strange, initially putting in "a" will show that it is not currently stored, the lives is default yet the guesses is still 0, it is not updating guesses.
Then inputting "b" shows it is not stored and incorrect. However it does not add a value to incorrect.
Inserting "b" on the next input shows it is stored. However correctly displays lives.
Lastly this functionality doesnt seem to work at all when removing the
This functionality just seems really strange to me. Not sure where i am going wrong
Console output:
Objecthint:
hint: "the start of something"
id: 1
title: "initial"
value: 1
word: "initial"
Hangman.js:62 not stored
Hangman.js:77 lives5
Hangman.js:78 guesses0
Hangman.js:79 incorrect0
Hangman.js:72 not stored and incorrect
Hangman.js:77 lives5
Hangman.js:78 guesses1
Hangman.js:79 incorrect0
Hangman.js:52 stored
Hangman.js:77 lives4
Hangman.js:78 guesses1
Hangman.js:79 incorrect1
code:
const [letter, setLetter]=useState('')
const [letters, setLetters]=useState([])
const [guesses, setGuesses]=useState(0)
const [incorrect, setIncorrect]=useState(0)
const [lives, setLives]=useState(5)
var hangman = { id:1,title:"initial",word:"initial",hint:"the start of something",value:1}
const handleInputButton = (e) => {
e.preventDefault();
if (letter !== "" && letter !== " "){
if (letters.includes(letter))
{
console.log("stored")
// show that this letter is correct
}
// doesnt update lives when incorrect until second click of same character?
else{
if ( hangman.word.toUpperCase().includes(letter.toUpperCase()) ) {
console.log("not stored")
letters.push(letter)
setGuesses(guesses + 1)
// update display here
}
else{
letters.push(letter)
setIncorrect(incorrect + 1)
setLives(lives - 1 )
console.log("not stored and incorrect")
}
}
}
console.log("lives" + lives)
console.log("guesses" +guesses)
console.log("incorrect" + incorrect)
}
const [Attempt, setAttempt] =([]);
const handleSubmitButton = (e) => {
e.preventDefault();
console.log("submit")
// put request here to post
}
const handleHint = (e) => {
e.preventDefault();
// reveal hint text here
console.log("hint")
}
return (
<div className='app'>
<br/> <br/> <br/> <br/> <br/> <br/>
{/* display will go here */}
<img alt="hangman figure"/>
<br/> <br/>
{/* current lives will go here */}
<p> lives: {lives} </p>
{/* attempted letters will go here */}
<ul> attempted letters:
{letters.map(letter=>(
<li className="tag auto" key={letters.indexOf(letter)}> <p> {letter} </p> </li>
))}
</ul>
<Form>
<div className="form-group">
<input value={letter} onChange={(e)=>setLetter(e.target.value)}
type="text" className="form-control stuff" id="letter" placeholder="Enter Letter" required/>
</div>
<br/> <br/>
<Button onClick={handleInputButton} type="buton" className="btn btn-primary submit" id="submit">Submit</Button>
</Form>
<br/> <br/> <br/> <br/>
{/* hint button */}
<Button>Hint</Button>
<p> {hangman.hint} </p>
<br/> <br/>
{/* finalise button */}
<Button onClick={handleSubmitButton} type="buton" className="btn btn-primary submit" id="submit">Finalize</Button>
{/* {showResult ? (
<div className='result'>
Your result is {result} of {questionList.length}
</div>
) : (
<>
<div className='question'>
<div className='index'>
<span>Question {current + 1}</span>/{questionList.length}
</div>
<div className='text' onCopy={handleCopy} >{questionList[current].question}</div>
</div>
<div className='answer-section'>
{questionList[current].answers.map((answer, index) => (
<button key={answer.id} onClick={()=> handleAnswerButton(answer.correct, startTime, timeLimit)}>{answer.content}</button>
))}
</div>
</>
)} */}
</div>
);
}

Set filter value conditionally using radio button and input search in react table

export const DefaultColumnFilter11 = ({
column: {
filterValue,
setFilter,
preFilteredRows: { length },
},
}) => {
const [condVal, setcondVal] = useState("");
return (
<div>
<input
type="radio"
value=">"
name="cond"
onChange={(event) => setcondVal(event.target.value)}
/>{" "}
<
<br />
<input
type="radio"
value="<"
name="cond"
onChange={(event) => setcondVal(event.target.value)}
/>
>
<br />
<Input
value={filterValue|| ""}
onChange={(e) => {
setFilter( {condVal} && (e.target.value || undefined));
}}
placeholder={`${length}`}
/>
</div>
);
};
This is the code and I want to filter the column using radio button condition greater than ">" and less than "<" that should be applied to the input search.
Essentially I have some data that I would like to filter using radio buttons.
Selecting a button of a particular value should only cause those objects with that value as their property to be rendered.

How to create multiple input fields on click

I have a drop-down where I have several option, what I want to do is which ever option is selected I want to create that much of input fields
On change of select I am doing this
const Select_change = (e) => {
let val = parseInt(e.target.value);
console.log(val);
switch (val) {
case 2:
setinputHolder((inputHolder) => [...inputHolder, 2]);
case 3:
setinputHolder((inputHolder) => [...inputHolder, 3]);
case 4:
setinputHolder((inputHolder) => [...inputHolder, 4]);
console.log(inputHolder);
default:
setinputHolder((inputHolder) => [...inputHolder, val]);
}
};
<select
onChange={Select_change}
name="Select_op"
className="form-control"
ref={register({ required: 'Please select IOT hub' })}>
<option value={1}>1</option>
<option value={2}>2</option>
<option value={3}>3</option>
<option value={4}>4</option>
</select>
I have created one state initial which is set to be 1 as I want to show one input field,after this what I am doing is
const [inputHolder, setinputHolder] = useState([1]);
I am looping the input field on this basis
{inputHolder.map((li, index) => (
<div className="col-12 col-sm-12 col-md-8 col-lg-4 col-xl-4">
<div className="form-group input_form_label">
<input
type="text"
name="device_name"
id="device_name"
className="form-control"
placeholder="Device Name"
/>
<label className="common_label_form" htmlFor="device_name">
Device Name
</label>
</div>
</div>
))}
But it is not working as expected, what If I have unknown nos in my drop-down let say 100, so I can not use switch to 100, I want a dynamic solution which will work fine.
Here is my working code sandbox for better understanding
Do below changes in your code
const Select_change = (e) => {
let val = parseInt(e.target.value);
setinputHolder(val);
};
and while making input based on selected value
{[...Array(inputHolder).keys()].map(...)
so your logic will look like below code
<div className="row">
{[...Array(inputHolder).keys()].map((li, index) => (
<div className="col-12 col-sm-12 col-md-8 col-lg-4 col-xl-4">
<div className="form-group input_form_label">
<input
type="text"
name="device_name"
id="device_name"
className="form-control"
placeholder="Device Name"
/>
<label className="common_label_form" htmlFor="device_name">
Device Name
</label>
</div>
</div>
))}
</div>
https://codesandbox.io/s/boring-dew-k1chw?file=/src/App.js

Field array with one field at initial

I am trying to use the concept of field array because in my app a user should be able to fill multiple value for same kind of field. I could do as per redux-form field array example, however, in an example there is no initial field we have to first click on add member and then only we can have the field to fill the value but i need one field initially and then add further field if user wants to.
I tried from the redux-form example but its not allowing me to input the value at all. Here is the demo
https://codesandbox.io/s/n47qr2pvzl
The format of that field value should be like this
general: {
general_information: {
members: [
{
name: ''
},
{
name: ''
}
]
}
}
Here is the code
const renderMembers = ({ fields, meta: { touched, error, submitFailed } }) => (
<ul>
<li>
<button type="button" onClick={() => fields.push({})}>
Add Member
</button>
{(touched || submitFailed) && error && <span>{error}</span>}
</li>
{fields.map((member, index) => (
<li key={index}>
<button
type="button"
title="Remove Member"
onClick={() => fields.remove(index)}
/>
<h4>Member #{index + 1}</h4>
<Field
name={`${member}.name`}
type="text"
component={renderField}
label="Name"
/>
</li>
))}
</ul>
);
const FieldArraysForm = props => {
const { handleSubmit, pristine, reset, submitting } = props;
return (
<form onSubmit={handleSubmit}>
<Field
name="general.general_information.clubName"
type="text"
component={renderField}
label="Club Name"
/>
<Field
name="general.general_information.members.name"
type="text"
component={renderField}
label="Name"
/>
<FieldArray
name="general.general_information.members"
component={renderMembers}
/>
<div>
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
);
};
According to Redux-Form, we can set the initial fields by specifying it like (in your case):
export default reduxForm({
form: "fieldArrays", // a unique identifier for this form
validate,
initialValues: {"general": {
"general_information": {
"members": [
{}
]
}
}
}
})(FieldArraysForm);
Here is the live demo
Hope it helps :)

Reactjs Instant search

I have a JSON schema which I'm mapping through the page and then rendering. Now I want to filter through an only search query and render only the search results.
Listing.jsx
<div id="searchbar">
<Hero>
<Section>
<Container>
<Heading style={{ color: "white" }}>SEARCH</Heading>
<Field>
<Control>
<Input
onChange={this.onChangeSearch}
name="query"
type="text"
placeholder="Enter query"
value={query}
/>
</Control>
</Field>
</Container>
</Section>
</Hero>
</div>
<div>
{pageItems.map(data => (
<div key={data.id}>
{data.status === true ? (....) : (...)}</div>}
How can I show only relevant search results in instant search/real-time search?
As per comments/suggestions, I'd like the search based on a specific array or entire JSON object to search.
This is my onChange event which returns the whole JSON object in the console.
onChangeSearch = evt => {
this.setState({
[evt.target.name]: evt.target.value
});
this.state.items.map(data => {
return console.log(data);
});
};

Categories