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}`);
};
Related
Essentially I have a select dropdown that is being populated by an API.
If you look at the following code snippet, I essentially created an array of IDs called "first" and made it the value for the first select option above the map that I've done to populate the rest of the select.
Now in my handleChange when I log the value of a selected option it returns the value of the given option in an array of string numbers.
--> Example... if user selects the second option ['1']
When the user selects 'All IDs' that's where the issue is. When that option is selected whats logged is ---> ['1,2,6,8,15,16,17,20,22,23,24,25,26,27,30,32,33,34,36']
I understand that I could use the split method but it crashes for any other option that's selected.
How could I get around that?
const DropDown = ({ list = [], title, onChange }) => {
const handleChange = (e) => {
const { value } = e.target
const arr = [value]
console.log(arr)
// onChange(Number(value))
}
const first = list.map((list) => list.id)
return (
<>
<select onChange={handleChange}>
<option value={first}>{title}</option>
{list.map((item) => (
<option key={item.id} value={item.id}>
{item.name}
</option>
))}
</select>
</>
)
}
e.target.value is a string, so you'll need to change this:
const arr = [value]
to
const arr = value.split(",").map(Number);
You can use whatever you want as the value (key) of the "All" option. For example, in the following, I've used "all" as the key and handled that specifically in the handleChange handler.
const DropDown = ({ list = [], title, onChange }) => {
const handleChange = (e) => {
const { value } = e.target;
if (value === "all") {
onChange(list.map((l) => l.id));
} else {
onChange([parseInt(value, 10)]);
}
};
return (
<>
<select onChange={handleChange}>
<option value="all">{title}</option>
{list.map((item) => (
<option key={item.id} value={item.id}>
{item.name}
</option>
))}
</select>
</>
);
};
You can use value.split(",") as well, which would work for your specific example but would not be sufficient if you need to handle different types of items in the list (perhaps strings that could contain their own ,s).
Here's the above code in action
import React from 'react';
import { makeStyles} from '#material-ui/core/styles';
import {Select, MenuItem} from '#material-ui/core';
import useState from 'react';
const test = () => {
const data = [
{TITLE : "Festival", PRIORITY : 3, STEP : 1},
{TITLE : "Headphone", PRIORITY : 2, STEP : 2},
{TITLE : "Mountain", PRIORITY : 1, STEP : 1}
]
return (
<>
{
data.map((info) => (
<div>
<div>{info.TITLE}</div>
<Select value={info.PRIORITY}>
<MenuItem value={1}> 1 </MenuItem>
<MenuItem value={2}> 2 </MenuItem>
<MenuItem value={3}> 3 </MenuItem>
</Select>
<Select value={info.STEP}>
<MenuItem value={1}> 1 </MenuItem>
<MenuItem value={2}> 2 </MenuItem>
<MenuItem value={3}> 3 </MenuItem>
</Select>
</div>
))
}
</>
)}
export default test;
In this code, I'm trying to control PRIORITY value and STEP value respectively.
I'm having trouble because, In my Data array, I have three items. Therefore, If I add
const [priority, setPriority] = useState(undefined);
const [step, setStep] = useState(undefined);
const priorityChange = (e) => {
setPriority(e.target.value)
};
const stepChange = (e) => {
setStep(e.target.value)
};
and put this value in
<Select value={priority} onChange={priorityChange}></Select>
...
<Select value={step} onChange={stepChange}></Select>
...
this item,
Every item gets the same value, therefore I'm unable to control each PRIORITY and STEP value.
How can I control each item? I need some help.
I might misspell. Please be understandable!
Firstly your data array is not hooked to any state managing variable. So when you try showing values initially from the data array and then try showing the updated data from the hooks variable when an action is trigged, it is obvious to cause some clash and hence fail to show the updated values. One way to get around this would be, to associate the initial data with a state hook and then update the data array accordingly. It is also important that correct data is updated that corresponds to the action triggered, so here we'd want to make sure that each object of the collection is unique, this could be accomplished by assigning an id attribute on each object. Further up, we can find out the object on which the action was taken on, mutate the property value and then re-construct the array using the state hook function to re-render with the correct updated value(s).
Kindly refer to the below code and read the comments to get a clearer idea.
import React, { useState } from "react";
const App = () => {
const [data, setData] = useState([
{ id: Math.random(), TITLE: "Festival", PRIORITY: 3, STEP: 1 },
{ id: Math.random(), TITLE: "Headphone", PRIORITY: 2, STEP: 2 },
{ id: Math.random(), TITLE: "Mountain", PRIORITY: 1, STEP: 1 }
]); //id attribute is added to each object to make sure every object in the array is unique.
const priorityChange = (e, id) => {
//This function should accept event and id arguments, to identify and update
//values correctly.
const index = data.findIndex((item) => item.id === id); //find the index of the object (item) whose priority needs to be updated.
const arr = [...data]; //Copy original array data to constant arr.
arr[index].PRIORITY = e.target.value; //mutate the PRIORITY property's value
setData([...arr]); //Set data to the new array with updated value.
};
const valueChange = (e,id) => {
//This function should accept event and id arguments, to identify and update
//values correctly.
const index = data.findIndex((item) => item.id === id); //find the index of the object (item) whose priority needs to be updated.
const arr = [...data];
arr[index].STEP = e.target.value; //mutate the STEP property's value
setData([...arr]); //Set data to the new array with updated value.
};
return (
<>
{data.map((info) => (
<div key={Math.random()}>
<div>{info.TITLE}</div>
<select
value={info.PRIORITY}
onChange={(e) => {
priorityChange(e, info.id); //pass event object and id corresponding to each array object.
}}
>
<option value={1}> 1 </option>
<option value={2}> 2 </option>
<option value={3}> 3 </option>
</select>
<select
value={info.STEP}
onChange={(e) => {
valueChange(e, info.id); //pass event object and id corresponding to each array object.
}}
>
<option value={1}> 1 </option>
<option value={2}> 2 </option>
<option value={3}> 3 </option>
</select>
</div>
))}
</>
);
};
export default App;
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 have a html5 input with an associated datalist inside a React controlled component. I want to clear the text when the input field is clicked or receives focus so all options are displayed for selection. I've followed Alfred's excellent answer in this question but am unable to achieve quite the same result in a React controlled component. Unfortunately, calling blur inside the onClick handler prevents my users from typing more than a single character because focus is (of course) lost.
How can I maintain the ability for users to type but clear the text and show the full set of options whenever the text box is clicked?
import React, { useState } from "react";
const MyForm = () => {
const [options, setOptions] = useState(["Apples", "Oranges", "Bananas", "Grapes"]);
const handleChange = (event) => {
event.target.blur();
};
const clear = (event) => {
event.target.value = "";
};
return (
<>
<input
type="input"
list="optionsList"
onChange={handleChange}
onFocus={clear}
placeholder="Select an option"
/>
<datalist id="optionsList">
{options.map((o) => (
<option key={o}>{o}</option>
))}
</datalist>
</>
);
};
export default MyForm;
Note that I've also tried a version of this that calls clear onClick rather than onFocus. That keeps me from needing to call blur() in handleChanges so the problem typing is solved. But, this requires that I click twice to see the full set of options because the list of options seems to be presented before the box is cleared.
Saw your comment on one of my question, so I figured I'd post it here as an answer instead.
Based on your use case, here is what I think you will need
import React, { useState } from "react";
const MyForm = () => {
const [options, setOptions] = useState(["Apples", "Oranges", "Bananas", "Grapes"]);
const handleChange = (event) => {
if (!event.nativeEvent.inputType) {
event.target.blur();
}
};
const clear = (event) => {
event.target.value = "";
};
return (
<>
<input
type="input"
list="optionsList"
onChange={handleChange}
onClick={clear}
onFocus={clear}
placeholder="Select an option"
/>
<datalist id="optionsList">
{options.map((o) => (
<option key={o}>{o}</option>
))}
</datalist>
</>
);
};
export default MyForm;
In order to prevent handleChange from blocking text input normally, you will have to check for event.nativeEvent.inputType, as onChange triggered by clicking on datalist will not have an inputType value. So in this case we will only perform the input blur when it is populated by datalist and keep the focus for any other events.
I have also added an additional onClick handler to clear the input regardless whether the input is already in focus or not.
I guess you actually want to have input value as a state, and not the options.
Therefore possible controlled component implementation should be:
const options = ["Apples", "Oranges", "Bananas", "Grapes"];
const EMPTY_INPUT = "";
const MyForm = () => {
const [value, setValue] = useState(EMPTY_INPUT);
const onFocusClear = () => {
setValue(EMPTY_INPUT);
};
const onChange = ({ target: { value } }) => {
setValue(value);
};
return (
<>
<input
value={value}
type="input"
list="optionsList"
onChange={onChange}
onFocus={onFocusClear}
placeholder="Select an option"
/>
<datalist id="optionsList">
{options.map((o) => (
<option key={o}>{o}</option>
))}
</datalist>
Value: {value}
</>
);
};
And making it an uncontrolled component is pretty simple by removing the onChange. Now you have the input value in ref.current.value (Not so useful use case, just an example).
const MyForm = () => {
const inputRef = useRef();
const onFocusClear = () => {
inputRef.current.value = ''
};
return (
<>
<input
type="input"
list="optionsList"
onFocus={onFocusClear}
placeholder="Select an option"
/>
<datalist id="optionsList">
{options.map((o) => (
<option key={o}>{o}</option>
))}
</datalist>
</>
);
};
I am looping through an array in react using map function to return option tags for HTML select tag. But it does not seem to work. Project_titles array is properly populated with data.
I have used same code in some other place and it is working there.
render() {
<select
id="sel4"
onChange={event => this.setState({ project: event.target.value })}
>
{this.func()}
</select>;
}
func() {
this.state.project_titles.map(function(title, i) {
return (
<option key={i} value={title}>
{title}
</option>
);
});
}
Select tag should get populated with options but it is empty.
This works. The issue with your code is you are not returning the final Options array from you func() function.
render(){
<select
id="sel4"
onChange={event => this.setState({ project: event.target.value })}
>
{this.func()}
</select>;
};
func = () => {
return this.state.project_titles.map(function(title, i) {
return (
<option key={i} value={title}>
{title}
</option>
);
});
};