How to add items in select dynamically in react? - javascript

Could you please tell me How to add items in select dynamically in react ?
I am getting response from server (name , label etc).For example I just mock my response and after two second I fetch that .
In my example I have two select box or drop down .first dropdown have value “one” and “two”(which is given as options in json).
In json there is one more option dependentField it mean the field is dependent on another field (value mentioned is dependent).In my example second field is dependent on first field.
So the value of second select or dropdown field will be ["three", "four"] if first select box or dropdown value id one.
So the value of second select or dropdown field will be ["five", "six"] if first select box or dropdown value id two.
So I need to watch the value of field as mention in hook form
https://react-hook-form.com/get-started
Can we dynamically add options
here is code
https://codesandbox.io/s/stoic-benz-lxb8i
useEffect(() => {
console.log("====");
(async () => {
var a = await FETCH_API();
console.log("sssss");
setState(a);
console.log(a);
})();
}, []);
const getForm = () => {
try {
return state.map((i, index) => {
switch (i.type) {
case "text":
return (
<div key={index}>
<label>{i.label}</label>
<input type="text" ref={register()} name={i.name} />
</div>
);
case "select":
if (i.watch) {
watch(i.name, null);
}
return (
<div key={index}>
<label>{i.label}</label>
<select name={i.name} ref={register()}>
{i.options.map((i, idx) => {
return (
<option key={idx} value={i}>
{i}
</option>
);
})}
/
</select>
</div>
);
default:
return <div>ddd</div>;
}
});
return <div>ddd</div>;
} catch (e) {}
};
I don’t wan’t want to do any harcoading like
useEffect(()=>{
},[‘first’])
can we watch or add useeffect dynamically to watch change dynamically ?
Any update

this is a simpl two select. Where frist select depend on second
import React,{useState, useEffect} from "react"
const App = () => {
const [state,setState] = useState({
option1:["one","two"],
option2: []
})
useEffect(()=> {
(async () => {
var a = await FETCH_API();
console.log("sssss");
setState({
...state,
option2: a
});
console.log(a);
})();
},[state.option1])
return(
<div>
<select>
{
state.option1.map((i,idx)=>{
return(
<option key={idx} value={i}>
{i}
</option>
)
})
}
</select>
<select>
{
state.option2.map((i,idx)=>{
return(
<option key={idx} value={i}>
{i}
</option>
)
})
}
</select>
</div>
)
}
export default App

Related

cant properly display value from select menu

I have a component which is a select menu and I get the value selected from the select menu when it changes and then both values from the 2 select menus when I click the button but the value appears as [object Object] from the console and then I attached a screenshot of the alert output.
Can anyone see why from my code the values are not as expected in my Replay component as the values display properly on the actually menu it just doesn't seem to be the correct value in the Replay component?
screenshot of alert:
First component which renders the 2 select menus and button:
function Replay() {
const [firstActivity, setFirstActivity] = useState();
const [secondActivity, setSecondActivity] = useState();
const handleFirstChange = (value) => {
console.log("evt.target = ",(value));
setFirstActivity(value.name);
}
const handleSecondChange = (value) => {
setSecondActivity(value.name);
}
const handleClick = () => {
alert("values select are: ", firstActivity, secondActivity);
}
return (
<div className='top-container'>
<button onClick={handleClick}>Get select values!</button>
<div className='container'>
<Menu
onChange={handleFirstChange}
/>
<Menu
onChange={handleSecondChange}
/>
</div>
</div>
)
}
export default Replay;
2nd select menu component:
import React, {useState, useContext} from 'react';
import { GlobalContext } from "./Store";
function Menu(props) {
const [activities] = useContext(GlobalContext);
const handleMenuChange = (evt) => {
console.log("evt.target.value = ", evt.target.value);
props.onChange(evt.target.value);
}
const createOptions =
<>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</>
return (
<div className="container">
<select
className="select"
defaultValue="1"
onChange={handleMenuChange}
>
{createOptions}
</select>
</div>
);
}
export default Menu;
First Problem:
alert doesn't take multiple arguments. This is one of the many reasons not to use it for debugging. Use console.log instead:
console.log("values select are: ", firstActivity, secondActivity);
Second Problem:
You're passing the value to your change handler function(s):
props.onChange(evt.target.value);
A value which you just logged as a plain value and observed that it's just a number:
console.log("evt.target.value = ", evt.target.value);
Then in that handler function you again observe that the value passed to it is just a number (or at least a numeric string):
console.log("evt.target = ",(value));
Then what do you try to do with that value? This:
setFirstActivity(value.name);
Why do you expect it to have a name property? Where did that property come from? It's just a plain value. Use the value:
setFirstActivity(value);
Example

I want to be able to select multiple options in the dropdown, how can I change my code to do that?

Currently, my dropdown looks like this. I can only select one of the options. I want to be able to select multiple options when clicking. I tried adding multiple in <select> but that doesn't work. How can I make the dropdown allow multiple selections?
const SelectMultipleDropdown = props => {
const {
name,
required,
placeholder,
handleChange,
choices,
value,
fieldValid,
setFieldValid
} = props;
const [currentSelection, setCurrentSelection] = useState("");
// the default value is empty string ""
// invalid/greyed out value is empty string ""
return (
<div>
<p className="field-component-title">
{name}
{required ? <span className="required-star"> *</span> : ""}
</p>
<select
className={`dropdown-select-field field-component-input-box ${
currentSelection === ""
? "dropdown-select-grey"
: "dropdown-select-black"
} ${(() => {
return fieldValid ? "" : "dropdown-select-invalid";
})()}`}
type="text"
onChange={e => {
e.persist();
setCurrentSelection(e.target.value);
handleChange(e);
setFieldValid(true);
}}
value={value}
>
<option value={""}>{placeholder}</option>
{choices.map(({ value, text }, index) => (
<option key={index} value={value}>
{text}
</option>
))}
</select>
</div>
);
};
I'm a bit unclear on the error or undesired behavior you get here. But, here's my try. First multiple works a bit weird depending on browser and OS as described here.
I'm guessing that's not what you're describing tho. I'm guessing the problem is that you are 1. overwriting all your selected and 2. not mapping selected to your options.
So you need to start with an empty array for your selected elements if nothing is selected, then add to that array in the onChange() instead of overwrite the value there and finally add selected to the option when it's in your list of selected elements.
I would also add it appears you are storing the value at this level component and a higher level component thru a callback. It is generally a best practice to store the value in one spot. I'm not sure the best place from this bit of code. That might be best in another question.
const [currentSelection, setCurrentSelection] = useState([]);
return (
<div>
<p className="field-component-title">
{name}
{required ? <span className="required-star"> *</span> : ""}
</p>
<select
className={`dropdown-select-field field-component-input-box ${
currentSelection === ""
? "dropdown-select-grey"
: "dropdown-select-black"
} ${(() => {
return fieldValid ? "" : "dropdown-select-invalid";
})()}`}
type="text"
onChange={e => {
e.persist();
setCurrentSelection((current) => [...current, e.target.value]);
handleChange(e);
setFieldValid(true);
}}
>
<option value={""}>{placeholder}</option>
{choices.map(({ value, text }, index) => (
<option key={index} value={value} selected={currentSelection.includes(value)}>
{text}
</option>
))}
</select>
</div>
);
};
Note: if you want to support super old browsers you'd need to replace includes(currentValue) with indexOf(currentValue) > -1
I think in this component, your current Selection is a string, and use setCurrentSelection(e.target.value); can change currentSelection to another option.
You can change string to array, for instance, currentSelections. And change setCurrentSelections function to:
setCurrentSelections = (e) => {
const value = e.target.value;
let currentSelections = this.state.currentSelections.slice(0);
let index = currentSelections.indexOf(value);
if (index > -1) {
currentSelections.splice(index, 1);
} else {
currentSelections.push(value);
}
this.setState({ currentSelections: currentSelections });
}
And use React Component
class SelectMultipleDropdown extends React.Component {
constructor(props) {
super(props);
this.state = {
currentSelections: [],
}
}
setCurrentSelections = (e) => {
const value = e.target.value;
let currentSelections = this.state.currentSelections.slice(0);
let index = currentSelections.indexOf(value);
if (index > -1) {
currentSelections.splice(index, 1);
} else {
currentSelections.push(value);
}
this.setState({ currentSelections: currentSelections });
}
onChange = (e) => {
e.persist();
this.setCurrentSelection(e);
this.porps.handleChange(e);
this.props.setFieldValid(true);
}
render() {
const {
name,
required,
placeholder,
choices,
value,
} = props;
return (
<div>
<p className="field-component-title">
{name}
{required ? <span className="required-star"> *</span> : ""}
</p>
<select
className={''}
type="text"
onChange={this.onChange}
value={value}
>
<option value={""}>{placeholder}</option>
{choices.map(({ value, text }, index) => (
<option key={index} value={value} selected={this.state.currentSelections.includes(value)}>
{text}
</option>
))}
</select>
</div>
);
}
}

How to add element in array

Hi all I have following code:
const category = useSelector(state => state.category.category);
const list = [];
const addlist = (id, name) => {
const data = {
id: name,
};
list.push(data);
};
I am getting from my state category. Then I am creating empty list array and finally I have addlist function who is added item in my list array.
here is my select options:
return(
<div>
<select name="cars" id="cars">
<option value="" selected disabled hidden>
choose category
</option>
{category?.map((item, idx) => (
<option
key={item.id}
value={idx}
disabled={active}
onClick={() => addlist(item.id, item.name)}
>
{item.name}
</option>
))}
</select>
</div>
)
I am trying to implement following, when some option will be clicked it should be automatically added in array. But after clicking nothing was happening. Please help to resolve this issue.
As suggested in the comment section, for similar scenarios where you'd like to keep values for example in an array in your component you should use useState hook.
You can import useState as:
import { useState } from 'react'
A basic idea would be the following - see how the onClick has changed:
const YourComponent = () => {
const category = useSelector(state => state.category.category);
// here you can create a list state with an initial empty array
const [list, setList] = useState([])
return(
<div>
<select name="cars" id="cars">
<option value="" selected disabled hidden>
choose category
</option>
{category?.map((item, idx) => (
<option
key={item.id}
value={idx}
disabled={false} // originally here was active
onClick={() => setList(prevState => [...prevState, {
id: item.name
}])}
>
{item.name}
</option>
))}
</select>
</div>
)
}
But the essential part other than creating a list state would be:
setList(prevState =>
[...prevState, { id: item.name }]
)
Suggested documentation to read is Using the State Hook.

How to store a value based on another attribute value

I need to display some attribute of an element in a select, and store the displayed attributes in a value and a different attribute of the same element in another value.
render() {
const refertiItems = this.state.referti.map((referti, i) => {
return (
<option key={referti.hash_referto}>
{referti.tipo_esame}-{referti.data_esame}
</option>
)
});
return(
<Label for="type" text="Descrizione Referto" />
<select
name="descrizioneReferto"
placeholder="Selezionare Referto"
onKeyPress={this.onEnter}
value={this.state.referti.descrizioneReferto}
onChange={this.handleInputChange}
>
<option default value="vuoto"></option>
{refertiItems}
</select>
So in this code i can store {referti.tipo_esame} and {referti.data_esame} in descrizioneReferto. I also need to store {referti.hash_referto} inside codiceReferto. Any advice?
You can access the key of the option element in the onChange function like this:
handleInputChange = (event, child) => {
this.setState({
descrizioneReferto: event.target.value,
codiceReferto: child.key
});
}
To use the material-ui select, change your code to:
<Select
value={this.state.referti.descrizioneReferto}
name="descrizioneReferto"
onKeyPress={this.onEnter}
placeholder="Selezionare Referto"
onChange={this.handleInputChange}>
<MenuItem value="vuoto"/>
{refertiItems}
</Select>
and
const refertiItems = this.state.referti.map((referti, i) => {
return <Menu key={referti.hash_referto}>
{referti.tipo_esame}-{referti.data_esame}
</option>
});

When selecting an option in a dropdown, how do I change the state with onChange but with a value other than the one inside the option tags

Need some help with dropdowns. I can't seem to figure out a way to pass in the ID specific to that particular dropdown <option> so that when the user makes a selection that value can be used (for example to setState). The usual case is to read the value of the dropdown itself, but in my case I don't want the displayed value but another value that is 'behind the scenes' or hidden.
Please note I've already researched about controlled components in react for forms etc, this issue is a bit different and my attempts to find an answer have come up empty.
I'm using react and javascript but I think if you know a little about javascript you may be able to help.
The dropdowns are set up like shown below where on changing the dropdown selection it runs the function handleStatusChange.
<select
id="inputIdentity"
className="select-form"
onChange={this.handleStatusChange}
>
<option value="" hidden>
please choose
</option>
<option>status1</option>
<option>status2</option>
<option>status3</option>
</select>
In actual practice the options are mapped out from data fetched via an api as they can be altered in the backend:
<select
id="inputIdentity"
className="form-control content-input"
onChange={this.handleStatusChange}
>
<option value="" hidden>
Please Choose
</option>
{statusData ? (
statusData.map((status) => (
<option>{status.title}</option>
))
) : (
<option>Loading...</option>
)}
</select>
this.handleStatusChange checks the value of the event (which is the act of changing the selection in the dropdown, the value is accessed with: e.target.value) to read the value inside the <option> that was chosen... The method for reading the chosen dropdown value is something like:
handleStatusChange = (e) => {
this.setState({
// set it to state
status: e.target.value
});
};
I
This is the standard way to do it.
Now we get back to the question - is there a way to read a value from each dropdown that is NOT shown (read from e.target.value) instead, ie. if they each had an ID or something, how do I pass that in so that e.target.value would be able to access this id.
If you take a look at the version where I map out (or loop out if you aren't familiar with the map function) the <option> tags and in each iteration I pass in the title with {status.title}. I can access the id with status.id but the onChange handler is in the <select> tag and can't be within the map / loop, so to handle it by passing in the id into the onChange handler is not possible either.
What would be the correct way for the onChange handler to have access to that specific value which is not displayed between <option> tags?
You can keep the options in your component state and use the array method find to find the option that corresponds to the selected option and use that.
Example
class App extends React.Component {
state = {
options: [
{ value: "status1", label: "Status 1", secretValue: "foo" },
{ value: "status2", label: "Status 2", secretValue: "bar" },
{ value: "status3", label: "Status 3", secretValue: "baz" }
],
selectedOption: ""
};
handleStatusChange = e => {
const { value } = e.target;
this.setState(prevState => {
const { secretValue } = prevState.options.find(
option => option.value === value
);
console.log(secretValue);
return { selectedOption: value };
});
};
render() {
const { options, selectedOption } = this.state;
return (
<select value={selectedOption} onChange={this.handleStatusChange}>
<option value="" hidden>
please choose
</option>
{options.map(option => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
you can pass that value to the loop showing the Options.
{statusData ? (
statusData.map((status) => (
<option value={status.value}>{status.title}</option>
))
) : (
<option>Loading...</option>
)}
and in order to do that you have to modify your array statusData.
hiddenData = ['a', 'b', 'c'];
statusData.map((s, index) => {
s.value = hiddenData[index]
return s;
});
is there a way to read a value from each dropdown that is NOT shown (read from e.target.value) instead, ie. if they each had an ID or something, how do I pass that in so that e.target.value would be able to access this id.
e.target is a reference to the HTMLSelectElement where the change occurred. You can find the option with the matching value in its options list, and then use that HTMLOptionElement's properties, like this:
handleStatusChange({target}) {
const value = target.value;
const optionElement = Array.from(target.options).find(opt => opt.value === value);
// If found, use information from `optionElement` to find the
// entry in `statusData` in a state change, e.g.:
if (optionElement) {
const id = optionElement && optionElement.id;
if (id) {
this.setState(state => {
const entry = state.statusData.find(e => e.id === id);
if (entry) {
// Use `entry`'s information
}
}
}
}
}
React example, using a details property on the entries in statusData:
class Example extends React.Component {
constructor(...args) {
super(...args);
this.handleStatusChange = this.handleStatusChange.bind(this);
this.state = {
detail: "",
statusData: [
{id: "one", title: "One", detail: "Details for one"},
{id: "two", title: "Two", detail: "Details for two"},
{id: "three", title: "Three", detail: "Details for three"}
]
};
}
handleStatusChange({target}) {
const value = target.value;
const optionElement = Array.from(target.options).find(opt => opt.value === value);
const id = optionElement && optionElement.id;
if (id) {
this.setState(state => {
const entry = state.statusData.find(e => e.id === id);
if (entry) {
return {
detail: entry.detail
}
}
});
}
}
render() {
const {statusData, detail} = this.state;
return (
<div>
<select
id="inputIdentity"
className="form-control content-input"
onChange={this.handleStatusChange}
>
<option value="" hidden>
Please Choose
</option>
{statusData ? (
statusData.map((status) => (
<option id={status.id}>{status.title}</option>
))
) : (
<option>Loading...</option>
)}
</select>
<div>Detail: {detail}</div>
</div>
);
}
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Categories