Its suppose return component that realize dropdown list by getting array of strings. Its probably some mistake how use elements of array.
import React from 'react'
class DropDownList extends React.Component {
renderDropDownList = () => {
const { dropDownDownData } = this.props
return (
<div className="book-shelf-changer">
<select>
dropDownDownData.map(function(item){
<option key = {item} value={item}>{item}</option>
})
</select>
</div>
)
}
render() {
const optionList = ['Move to...','Currently Reading','Want to Read','Read','None']
return this.renderDropDownList(optionList)
}
}
export { DropDownList }
I think it's just because you have forgotten some curly braces to call dropDownData function and your function is not interpreted as Javascript function. Add a return to your map function too.
It should work with this :
<select>
{dropDownDownData.map(function(item){
return (<option key = {item} value={item}>{item}</option>);
})}
</select>
You can also use ES6 syntax for your map expression :
<select>
{dropDownDownData.map(item => (<option key = {item} value={item}>{item}</option>))}
</select>
Related
import React from 'react'
export default function CurrencyRow(props) {
const {
currencyOptions
} = props
return (
<div>
<input type="number" className="input-box" />
<select>
{currencyOptions.map(option => (
<option key={option} value={option}>{option}</option>
))}
</select>
</div>
)
}
The key must always be unique for each element and Since the key is repeating in the array currencyOptions the errors shows up.
To avoid this error you can try it this way
array.map((element, index) => { /* ... */ })
You can read more about it at : Mozilla Docs
since the index is unique for each element you can use
currencyOptions.map(option,index => (
<option key={index} value={option}>{option}</option>
))
I want to get option's value and key when select onChange.
I know I can get option's value simplicity used event.target.value in onChangeOption function, but how can I get key?
<select onChange={this.onChangeOption} value={country}>
{countryOptions.map((item, key) =>
<option key={key} value={item.value}>
{item.name}
</option>
)}
</select>
You will need to pass value in key as a different prop.
From docs:
Keys serve as a hint to React but they don’t get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name:
Read: https://reactjs.org/docs/lists-and-keys.html
Passing key as a prop works obviously, but much quicker way could be to include the key as a custom attribute in your html.
class App extends React.Component {
constructor(props) {
super(props);
this.onSelect = this.onSelect.bind(this);
}
onSelect(event) {
const selectedIndex = event.target.options.selectedIndex;
console.log(event.target.options[selectedIndex].getAttribute('data-key'));
}
render() {
return (
<div>
<select onChange = {this.onSelect}>
<option key="1" data-key="1">One</option>
<option key="2" data-key="2">Two</option> </select>
</div>
);
}
}
ReactDOM.render( < App / > , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
A simple way of doing this is:
const functionCall = (event) => {
console.log(event.target.getAttribute('a-key'));
}
<button a-key={1} onClick={functionCall}>Press Me</button>
I put onClick but you can use any event.
You can pass anything through value. I think this solves your problem.
<select onChange={this.handleChange}>
{this.state.countryOptions.map((item, key) =>
<option key={key}
value={JSON.stringify({key, value:item.value})}>
//passing index along with value
{item.value}
</option>
)}
</select>
handleChange(e) {
let obj = JSON.parse(e.target.value)
// gives object{ key:country index, value: country value}
}
Imagine a component like this:
<Component data={[{id:'a23fjeZ', name="foo"}, ...]}`
Which renders a list of inputs, and gets in a data prop which is a collection (Array of Objects):
function Component ( props ){
// cached handler per unique key. A self-invoked function with a "cache" object
const onChange = (cache => param => {
if( !cache[param] )
cache[param] = e =>
console.log(param, e.target.name, e.target.value)
return cache[param];
}
)({});
return props.data.map(item =>
<input key={item.id} name={item.name} onChange={onChange(item.id)} />
}
}
As you can see, the key isn't being accessed, but is passed into a currying function which is handling the caching internally, to prevent "endless" creation of functions on re-renders.
I'm a beginner and have battle with this for days now!
Now, I will be happy to share you my final answer!
This is really easy -All you got to do is to declare an anonymous function! for an onClick on the item you wanna detect its key!
e.g
data.map((item) => (<div
className = "newItem" key = {item.id} onClick = {() = displayKey(item.id)}
>{item.value}</div>))
then your function can be thus;
will display any "val" passed in
const displayKey = (val) => {
console.log(val)
}
I hope I was able to help!
battling with a problem can be a pain in the ass!
Kind Regards .
So you do need to pass the key into the <option> as a prop, but since the <select> is a native field and handles changes internally it gets a little hard to get that key value back out.
Lets start one issue at a time, passing the prop into the option could be as simple as wrapping the option component like so and using the index prop as the new key prop.
const CustomOption = ({ value, children, index }) => (
<option key={index} value={value}>{value}</option>
);
Also note that we're creating a custom component wrapper above to swallow the index prop from being applied to <option /> itself as react doesnt like unknown props on dom elements.
Now if we could handle the selected event inside the option we would be done, but we can't do that. so we need to make a custom select as well:
class CustomSelect extends React.Component {
static propTypes = {
value: PropTypes.object,
onChange: PropTypes.func,
}
handleChanged = (e) => {
const newValue = e.target.value;
let newKey;
// iterate through our children searching for the <CustomOption /> that was just selected
React.children.forEach(this.children, (c) => {
if (c.props && c.props.index && c.props.value === newValue) {
newKey = c.props.key;
}
});
this.props.onChange(e, newKey);
}
render() {
return (
<select value={this.props.value} onChange={this.handleChanged}>
{this.props.children}
</select>
);
}
}
it has two props value, and onChange. Notice that we intercept the change event in order to find the index (the key) and we pass it along to the parent as the second parameter. This is not very nice but I can't think of another easy way to do this while still using the native <select> element.
Note you need to replace your usages of <select> and <optoin> to use these new classes, and assign the index prop along with the key prop on the option.
I'd like to know how to get the object properties from a json.
I got this fake API:
{
"Arreglo":[
{ "label": "Choose Wisely", "value": "Choose Wisely"},
{ "label": "Primer opción", "value": "1", "testvariable": [] },
{ "label": "Segunda opción"," value": "2" },
{ "label": "Tercer opción", "value": "3" }
]
}
This is my App.js :
import SelectComponent from './Components/SelectComponent';
import {Arreglo} from './FakeApis/SelectOptions';
function App() {
return (
<div className="App">
<SelectComponent items1 = {Arreglo}/>
</div>
);
}
And this is my form and how I set the state:
export default function SelectComponent(items1) {
console.log(items1.items1);
const[testVar, testFunction] = useState(false);
const [items] = React.useState(items1.items1);
<form>
<select onChange = {handleChange}>
{items.map(item => (
<option
key={item.value}
value={item.value}
label={item.label}
>
{item.label}
</option>
))}
</select>
</form>
In this function I'd like to know how to get the "testvariable"
const handleChange = event => {
console.log("The variable --->");
};
Hope I explained myself good.
regards!
Since your data doesn't have any unique identifying id, you can use the index of each item in the array as a reference point that you can use in your change handler.
To do this, first read your data into some piece of state. While your data is static now, this is good practice for when you start speaking to an actual API to fetch data.
Once you have that data available within your component (you can abstract this back into a separate Select Component, I just did it one file for ease of understanding), you can access the selected option by using the selectedIndex property of the event within the change event handler.
import {Arreglo} from './FakeApis/SelectOptions';
export default function App() {
// Read the data into state
const [data] = React.useState(Arreglo);
const handleChange = e => {
// The index of the selected option
const { selectedIndex } = e.currentTarget;
// Grab the element at that index
const selectedOption = data[selectedIndex];
// You can now access any property on that element, like testVariable
console.log(selectedOption.testvariable);
};
return (
<div className="App">
<select onChange={handleChange}>
{data.map(item => (
<option key={item.value} value={item.value} label={item.label}>
{item.label}
</option>
))}
</select>
</div>
);
}
To access the testVar your handleChange function must be inside the SelectComponent function just like the testVar:
export default function SelectComponent(items1) {
const[testVar, testFunction] = useState(false);
const [items] = React.useState(items1.items1);
const handleChange = event => {
// testVar can be called here
}
<form>
<select onChange = {handleChange}>
{items.map(item => (
<option
key={item.value}
value={item.value}
label={item.label}
>
{item.label}
</option>
))}
</select>
</form>
Something that you could do in order to solve your issue and have access to your data is to replace your select tag by the following:
<select onChange = {(event) => handleChange(event, items)}>
{items.map(item => (
<option
key={item.value}
value={item.value}
label={item.label}
>
{item.label}
</option>
))}
</select>
And let your handleChange function accept another parameter:
const handleChange = (event, items) => {
// items is now available in this block and you can get testvariable here.
console.log(`The variable ${items}`);
};
I want to get option's value and key when select onChange.
I know I can get option's value simplicity used event.target.value in onChangeOption function, but how can I get key?
<select onChange={this.onChangeOption} value={country}>
{countryOptions.map((item, key) =>
<option key={key} value={item.value}>
{item.name}
</option>
)}
</select>
You will need to pass value in key as a different prop.
From docs:
Keys serve as a hint to React but they don’t get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name:
Read: https://reactjs.org/docs/lists-and-keys.html
Passing key as a prop works obviously, but much quicker way could be to include the key as a custom attribute in your html.
class App extends React.Component {
constructor(props) {
super(props);
this.onSelect = this.onSelect.bind(this);
}
onSelect(event) {
const selectedIndex = event.target.options.selectedIndex;
console.log(event.target.options[selectedIndex].getAttribute('data-key'));
}
render() {
return (
<div>
<select onChange = {this.onSelect}>
<option key="1" data-key="1">One</option>
<option key="2" data-key="2">Two</option> </select>
</div>
);
}
}
ReactDOM.render( < App / > , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
A simple way of doing this is:
const functionCall = (event) => {
console.log(event.target.getAttribute('a-key'));
}
<button a-key={1} onClick={functionCall}>Press Me</button>
I put onClick but you can use any event.
You can pass anything through value. I think this solves your problem.
<select onChange={this.handleChange}>
{this.state.countryOptions.map((item, key) =>
<option key={key}
value={JSON.stringify({key, value:item.value})}>
//passing index along with value
{item.value}
</option>
)}
</select>
handleChange(e) {
let obj = JSON.parse(e.target.value)
// gives object{ key:country index, value: country value}
}
Imagine a component like this:
<Component data={[{id:'a23fjeZ', name="foo"}, ...]}`
Which renders a list of inputs, and gets in a data prop which is a collection (Array of Objects):
function Component ( props ){
// cached handler per unique key. A self-invoked function with a "cache" object
const onChange = (cache => param => {
if( !cache[param] )
cache[param] = e =>
console.log(param, e.target.name, e.target.value)
return cache[param];
}
)({});
return props.data.map(item =>
<input key={item.id} name={item.name} onChange={onChange(item.id)} />
}
}
As you can see, the key isn't being accessed, but is passed into a currying function which is handling the caching internally, to prevent "endless" creation of functions on re-renders.
I'm a beginner and have battle with this for days now!
Now, I will be happy to share you my final answer!
This is really easy -All you got to do is to declare an anonymous function! for an onClick on the item you wanna detect its key!
e.g
data.map((item) => (<div
className = "newItem" key = {item.id} onClick = {() = displayKey(item.id)}
>{item.value}</div>))
then your function can be thus;
will display any "val" passed in
const displayKey = (val) => {
console.log(val)
}
I hope I was able to help!
battling with a problem can be a pain in the ass!
Kind Regards .
So you do need to pass the key into the <option> as a prop, but since the <select> is a native field and handles changes internally it gets a little hard to get that key value back out.
Lets start one issue at a time, passing the prop into the option could be as simple as wrapping the option component like so and using the index prop as the new key prop.
const CustomOption = ({ value, children, index }) => (
<option key={index} value={value}>{value}</option>
);
Also note that we're creating a custom component wrapper above to swallow the index prop from being applied to <option /> itself as react doesnt like unknown props on dom elements.
Now if we could handle the selected event inside the option we would be done, but we can't do that. so we need to make a custom select as well:
class CustomSelect extends React.Component {
static propTypes = {
value: PropTypes.object,
onChange: PropTypes.func,
}
handleChanged = (e) => {
const newValue = e.target.value;
let newKey;
// iterate through our children searching for the <CustomOption /> that was just selected
React.children.forEach(this.children, (c) => {
if (c.props && c.props.index && c.props.value === newValue) {
newKey = c.props.key;
}
});
this.props.onChange(e, newKey);
}
render() {
return (
<select value={this.props.value} onChange={this.handleChanged}>
{this.props.children}
</select>
);
}
}
it has two props value, and onChange. Notice that we intercept the change event in order to find the index (the key) and we pass it along to the parent as the second parameter. This is not very nice but I can't think of another easy way to do this while still using the native <select> element.
Note you need to replace your usages of <select> and <optoin> to use these new classes, and assign the index prop along with the key prop on the option.
This is my react functional component, I am sending inputs as props which are to be displayed and then looping through the inputs to check which inputs are to be displayed according to condition. This is my component :-
const TopInputComponent = (props) => {
const inputs = props.inputs;
inputs.map((input,index)=>{
if(input.type == "textInput"){
return (<Textfield key={index}
onKeyDown={(event)=>{
if(event.key == "Enter"){
onFilterSelected({'min_price':parseInt(event.target.value)});
}
}}
label={input.placeholder}
floatingLabel
/> )
}else if(input.type == "selectInput"){
return (<div key={index}>
<label>{input.placeholder}</label>
<select >
<option value="1">1</option>
<option value="2">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</div>)
}
})
}
I am getting this Error :
"A valid React element (or null) must be returned. You may have
returned undefined, an array or some other invalid object."
There are two, three, possibly four problems:
You aren't returning anything out of the function, because you haven't returned the result of map.
A React component must return a single element or null, it can't return an array.
Within your map callback, you're only returning something if input.type is "textInput" or "selectInput", not if it's something else. That will leave undefined values in your resulting array. If those are the only two possible values, change else if(input.type == "selectInput"){ to just } else {. If not, handle the other cases.
floatingLabel in the Textfield's start tag seems odd, it will be a freestanding boolean attribute.
So you'll probably want to wrap those elements in something, perhaps a div (see *** lines):
const TopInputComponent = (props) => {
const inputs = props.inputs;
return <div>{inputs.map((input,index)=>{ // ***
if(input.type == "textInput"){
return (<Textfield key={index}
onKeyDown={(event)=>{
if(event.key == "Enter"){
onFilterSelected({'min_price':parseInt(event.target.value)});
}
}}
label={input.placeholder}
floatingLabel
/> )
} else { // *** Removed: if(input.type == "selectInput"){
return (<div key={index}>
<label>{input.placeholder}</label>
<select >
<option value="1">1</option>
<option value="2">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</div>)
}
})}</div>; // ***
}
Simplified live example:
const MyComponent = props => {
const {inputs} = props;
return <div>
{inputs.map((input, index) => <input key={index} type={input.type} name={input.name} value={input.value || ''} />)}
</div>;
};
ReactDOM.render(
<MyComponent inputs={[
{type: "text", name: "one"},
{type: "button", name: "btn", value: "Click me"}
]} />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Inside map you are returning the elements, that elements will group into an array by map (returns an array), You need to return the result of map also. You are returning an array but react component can't return an array, so wrap the map result inside a div.
Use this:
const TopInputComponent = (props) => {
const inputs = props.inputs;
return <div> { inputs.map((input,index)=>{ //added return
....
One more issue is, inside map if you don't return anything by default it will return undefined, you are using two condition, may be possible if none of them is true, in that case undefined will be returned. So always use a default case also, use it in this way:
return a.map(el => {
if(/*condition 1*/)
return //1;
else if(/*condition 2*/)
return //2;
else
return //3;
})
Check this example:
a = [1,2,3,4,5,6];
function withoutReturn () { a.map(i => i); };
function withReturn () { return a.map(i => i); };
console.log('withoutReturn', withoutReturn());
console.log('withReturn', withReturn())