how to pass array values to Formik select - reactjs

I am using Formik for a bunch of admin console forms that I have in my application. So far I did not have this use case.
My Formik forms use one of 2 custom components, either a Myinputtext(input box) or a MySelect(drop down). I dont have a need for any other components so far. Here is how my Myselect component looks like.
const MySelect = ({ label, ...props }) => {
const [field, meta] = useField(props);
return (
<div>
<label htmlFor={props.id || props.name}>{label}</label>
<select className={props.className} {...field} {...props} />
{meta.touched && meta.error ? (
<div className="error">{meta.error}</div>
) : null}
</div>
);
};
Over in the form I am passing values to this component like this
<MySelect className="select-input" label="Losing Player" name="losingPlayer">
<option value="">Select Losing Player</option>
<option value="player1">{state.Player1Name} </option>
<option value="player2">{state.Player2Name} </option>
All of this works for a few forms I have built so far. In the fourth form now, data coming back from the back end is coming as an array and I am trying to pass the array as input to the myselect component
<MySelect className="select-input" label="Losing Player" name="losingPlayer">
<option value="">Select Losing Player</option>
<option value="player1">{name of array object} </option>
This is failing and not providing the right result.
In the formik official docs it says there is a way to handle array objects like this
<Form>
<Field name="friends[0]" />
<Field name="friends[1]" />
<button type="submit">Submit</button>
</Form>
</Formik>
But my array size can be dynamic and I cannot hardcode, 0,1 like above.
I tried rendering the array inside the select component like this,
<MySelect className="select-input" label="Winning Player" name="winningPlayer">
{props.initialValues.map((player) => {
<option key={player} value={player}> {player} </option> })} </MySelect>
this does not throw any errors. but the drop down is displayed empty.
I am basically hoping to have the names in the array displayed as the dropdown. What is the right solution to tackle this?
This finally worked:-
return (
<div>
<label htmlFor={props.id || props.name}>{label}</label>
{!props.player ? <select className={props.className} {...field} {...props} />
:
<select className={props.className}>
{props.player.map((player) => {
return (
<option key={player} value={player}>
{player}
</option>
)
})}
</select>
}
{meta.touched && meta.error ? (
<div className="error">{meta.error}</div>
) : null}
</div>

You need to map your array and render options inside your select like this:
{options?.map(({ value }) => (
<option key={value} value={value}>
{value}
</option>
))}

Related

How to dynamically create a form that adds dynamic fields and nested array using the formik fieldArray

I am trying to create dynamic form with fieldArray in react. My code looks like this
<Formik initialValues={{
data:[],
}}
onSubmit={(values)=>{
console.log(values)
}}
>
{
(formik)=>(
<Form>
<h2>form starts here</h2>
<FieldArray name='data' render={
(arrayHelpers)=>{
return(
<div>
<button type='button' onClick={()=>arrayHelpers.insert(formik.values.data.length + 1,{question:'',quesType:'',answers:['']})}>Add</button>
{/* starts */}
{formik.values.data.map((d,index)=>(
<div key={index}>
<label htmlFor={`data.${index}.question`}>question</label>
<Field name={`data.${index}.question`} type='text' id={`data.${index}.question`}/>
<label htmlFor={`data.${index}.quesType`}>quesType</label>
<Field as="select" name={`data.${index}.quesType`}>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</Field>
</div>
// end
))}
</div>
);
}
}/>
<button type='submit'>submit</button>
</Form>
)
}
</Formik>
so after clicking add button my initialValue looksLike
data[{question:'',questype:'',answers:[]}]
Now after the select option I want to add a button that will add values in the answers array. I tried looping the d.answers but the answers property was not accessible even though I have the property. So, How to achieve this? Thanks in advance!

How to resolve "A control must be associated with a text label" on a datalist's option?

Building a dropdown and referencing Bootstrap 5 docs' on Datalists it shows an example of:
<label for="exampleDataList" class="form-label">Datalist example</label>
<input class="form-control" list="datalistOptions" id="exampleDataList" placeholder="Type to search...">
<datalist id="datalistOptions">
<option value="San Francisco">
<option value="New York">
<option value="Seattle">
<option value="Los Angeles">
<option value="Chicago">
</datalist>
Writing my component to handle drop downs I'm unsure how to resolve the ESLint error of:
A control must be associated with a text label
code:
import React from 'react'
import PropTypes from 'prop-types'
import { Field } from 'formik'
const Drop = ({ name, label, id, placeholder, options }) => {
return (
<div className="form-group mb-4">
<label htmlFor={name}>{label}:</label>
<Field
aria-label={`${name}-dropdown`}
name={name}
className="form-control"
list={id}
id={`${id}DropDown`}
placeholder={placeholder}
/>
<datalist id={id}>
{options.map((option, key) => (
<option key={key} value={option.toString()} data-value={option.toString()} />
))}
</datalist>
</div>
)
}
Drop.propTypes = {
name: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
options: PropTypes.array.isRequired,
}
export default Drop
Research
React Informed eslint associated control error after adding "Text" as control component
A control must be associated with a text label
Label must have associated control
In my option how can I resolve the ESLint error?
I was able to resolve my issue by adding an aria-label to the option so this:
<datalist id={id}>
{options.map((option, key) => (
<option key={key} value={option.toString()} data-value={option.toString()} />
))}
</datalist>
turned into:
<datalist id={id}>
{options.map((option, key) => (
<option key={key} value={option.toString()} aria-label={option.toString()} data-value={option.toString()} />
))}
</datalist>
after going through the docs and finding control-has-associated-label.

How to change page content base on selector option with reactjs

I got below code , every option will display a certain content in the same page , assuming im getting the content from an Array of objects how i will perform this using useState hook.
<FormControl className={classes.formControl}>
<InputLabel htmlFor="branch">Branch Name</InputLabel>
<Select
native
value={state.location}
onChange={handleChange}
inputProps={{
name: "location",
id: "branch",
}}
>
<option aria-label="None" value="" />
<option value={10}>North</option>
<option value={20}>East</option>
<option value={30}>West</option>
</Select>
</FormControl>
Store the selected value in a state and render conditionally based on the value of that state :
const [value, setValue] = useState(10)
return (
<>
<select value={value} onChange={(event) => setValue(event.target.value)}>
<option value={10}>North</option>
<option value={20}>East</option>
<option value={30}>West</option>
</select>
{value === 10 && <SomeComponent/>}
{value === 20 && <SomeOtherComponent/>}
{value === 30 && <SomeAnotherComponent />}
</>
)

Use image as icon with react-select

I would like to add an image as Icon with react-select. I did all right but I have a problem with the fact that, in react, images are written like this :
<img src={require(...)} />
So I use react-select like this :
const IconOption = (props) => (
<Option {... props}>
<div>
<img src={require(props.data.image)} />
</div>
</Option>
);
And then call for the select box :
render() {
return (
<Select
classNamePrefix="react-select"
placeholder={"Search..."}
onChange={this.handleChange}
components={{ DropdownIndicator: () => null, Option: IconOption }}
options={this.state.options}
openMenuOnClick={false}
styles={customStyle}
/>
);
}
I tried to write :
const IconOption = (props) => (
<Option {... props}>
<div>
{props.data.image}
</div>
</Option>
);
Which gives me :
./css/img/PROFILEPICTURE.jpg
It is exactly what I want to get, the path is correct. If I exactly write :
const IconOption = (props) => (
<Option {... props}>
<div>
<img src="./css/img/PROFILEPICTURE.jpg" />
</div>
</Option>
);
Image is correctly displayed.
If I write the first code, which is the one to get different picture for each item in selectbox, I got an error :
Any solution to not use require function for img in react?
Edit :
I also tried :
const IconOption = (props) =>
(
<Option {... props}>
<div>
<img src={props.data.image} />
{props.data.label}
</div>
</Option>
);
And i got not found images :
You just have to remove the require since your image is not part of the compiled react app:
const IconOption = (props) => (
<Option {... props}>
<div>
<img src={props.data.image} />
</div>
</Option>
);

REACTJS and ANTD: How to change form contents through <Select> option?

I am new to React and am currently using AntD in my ReactJS code. In my code, I have a select option that is supposed to change the form elements depending on what kind of form it is.
Here is my select:
<Form.Item label="Inquiry Type">
<Select>
<Option>
form 1
</Option>
<Option>
form 2
</Option>
<Option>
form 3
</Option>
</Select>
</Form.Item>
So what should happen is that when I choose Form 1, it should be able to show me all the contents of Form 1, and the same thing for Forms 2 and 3.
I am unsure about how to do this. I have read other questions but they do not answer mine.
Check this.
state = {
selectedForm: "form1"
};
changeForm = value => {
this.setState({
selectedForm: value
});
};
render() {
const { selectedForm } = this.state;
return (
<div>
<Select value={selectedForm} onChange={value => this.changeForm(value)}>
<Option value="form1">form 1</Option>
<Option value="form2">form 2</Option>
<Option value="form3">form 3</Option>
</Select>
{selectedForm === "form1" ? (
<Form1 />
) : selectedForm === "form2" ? (
<Form2 />
) : selectedForm === "form3" ? (
<Form3 />
) : ""}
</div>
);
}

Resources