can't select a options from my react-boostrap select element - javascript

I tried many ways to select some options from the select, but it didn't work. Could you help to solve my problem, please? When I do a console.log, the selected options change, but the frontend doesn't show it. It keeps the default option "Select the option." I am using react-bootstrap and firebase. I don't know what the error is. I was thinking about the browser, but it is not the problem.
class Formm extends Component {
constructor(props) {
super(props);
this.state = {
detail: "",
cost: 0,
category: ""
};
this.setCategory = this.setCategory.bind(this);
console.log(this.state);
}
setCategory = (e) => {
let index = e.target.selectedIndex;
this.setState({ category: e.target.value});
console.log(e.target.value)
};
render() {
const { detail, cost, category } = this.state;
return (
<div>
<FirebaseDatabaseProvider firebase={firebase} {...firebaseConfig}>
<FirebaseDatabaseNode path="category/">
{(data) => {
const { value } = data;
if (value === null || typeof value === "undefined") return null;
const values = Object.values(value);
return <div className="row justify-content-center">
<div className="form-group col-md-6">
<label htmlFor="">Insert the type:</label>
<select
onChange={this.setCategory}
value={category}
className="form-control"
>
<option value={null}>Select the option</option>
{values.map((value) => {
return (
<option key={value} value={value}>
{value}
</option>
);
})}
</select>
</div>
</div>;
}}
</FirebaseDatabaseNode>
</FirebaseDatabaseProvider>
</div>

It’s because you’re using “this” keyword inside of an arrow function that your set state doesn’t run.
“this” refers to the Class itself, but an arrow function, unlike a standard function, has no reference to the Class even though it’s defined within the Class.
Fortunately there’s an easy fix:
If you change setCategory to a function using the function keyword your code will run as you expect.

Related

Creating a filter for a drop down menu in React

I'm working on practicing with React and I'm creating a drop down menu, but in that when a user clicks on either a fruit or a vegetable, it'll filter and show on the page which item was selected.
I'm a little confused as my thought process was creating the changeItem method to filter out those specific items and call that as apart of the onChange in the HTML render, but I'm not sure if this is the correct way of approaching this and it's currently not rendering anything at the moment.
Any guidance would be appreciated
This is the code that I have so far:
class ItemList extends React.Component {
constructor(props) {
super(props)
this.changeItem = this.changeItem.bind(this)
this.state = {
value: 'all' // this would be the initial value
}
changeItem(event) {
this.setState({value: event.target.value} // where the value will be changed
}
}
render() {
return (
<>
<select onChange={this.changeItem} value:{event.target.value}>
<option value='all'>all</option>
<option value='cats'>fruits</option>
<option value='dogs'>vegetables</option>
</select>
<div className="item-list">
{this.props.items.map((item) =>
<SingleItem key={item.id}
item={item} />
)}
</div>
</>
);
}
}
I have prepared a sample which I think it will help you
import React from "react";
function SingleItem({ item }) {
return <div>{item?.type}</div>
}
class ItemList extends React.Component {
currentType = "";
constructor(props) {
super(props)
this.changeItem = this.changeItem.bind(this)
this.state = {
currentType: "all"
}
}
changeItem(event) {
this.setState({ currentType: event.target.value }) // where the value will be changed
}
filter(list) {
switch (this.state.currentType) {
case "cats":
return list.filter(i => i.type === "cats");
case "dogs":
return list.filter(i => i.type === "dogs");
default:
return list;
}
}
render() {
return <React.Fragment>
<select onChange={this.changeItem}>
<option value='all'>all</option>
<option value='cats'>fruits</option>
<option value='dogs'>vegetables</option>
</select>
<div className="item-list">
{this.props.items && this.filter(this.props.items).map((item) => <SingleItem key={item.id} item={item} />
)}
</div>
</React.Fragment>
}
}
export default function Page() {
let items = [
{
id: 1,
type: "cats",
name: "black cat"
},
{
id: 2,
type: "cats",
name: "white cat"
},
,
{
id: 3,
type: "dogs",
name: "Yellow dog"
}
];
return <ItemList items={items} />
}
I see a few different questions here, but I'll try to explain everything in a way that makes sense.
I'm going to suggest using functional components over class components. There's more explanation about the reasoning to using functional components in this answer as well, but to be brief here, the reasoning as explained in the linked answer is summarized as:
With the introduction of React hooks, it seems as though the React teams wants us to use functional components whenever possible (which better follows JavaScript's functional nature).
1.) It’s hard to reuse stateful logic between components
2.) Complex components become hard to understand
3.) Classes confuse both people and machines
First, we need an array of the possible options for the select menu:
const items = ["cats", "dogs"];
Next, we'll define the SingleItem component as simply as possible for the sake of this example:
function SingleItem({ item }) {
return <div>{item}</div>;
}
Then inside of ItemList we use useState to create a state variable so we can keep track of which item the user has selected:
function ItemList() {
const [selectedItem, setSelectedItem] = useState("all");
...
We also need to create a filtered version of the default list of items so that we can show only the selected item, or all items if "all" is selected:
const filteredItems = items.filter(
(item) => selectedItem === "all" || selectedItem === item
);
Then in our select, we set the value prop to the data saved in the selectedItem state variable. We also set the onChange prop to a function that will update selectedItem whenever the user selects a new item:
<select
onChange={(e) => setSelectedItem(e.target.value)}
value={selectedItem}
>
<option value="all">all</option>
<option value="cats">cats</option>
<option value="dogs">dogs</option>
</select>
Finally, we display the list items which should be shown by displaying each item in our filteredItems list:
<div className="item-list">
{filteredItems.map((item) => (
<SingleItem key={item.id} item={item} />
))}
</div>
Here's a full working example on codesandbox:

Hide Child Component Element After onClick using ReactJS

I'm new to React, learning by coding, here i have component A, which has select element with menuItems (all material ui), when user clicks select element and chooses from drop down, right after user has chosen whole component should go display:none, is this possible ? i mean user should not be able to see select element anymore on the page
English is not my mother language, so there might be mistakes.
suggestions/help is appreciated.
component A:
const A: React.FC<AProps> = (props) => {
const handleChange = (e: React.ChangeEvent<{ value: unknown }>) => {
const site = e.target.value as string;
dispatch(changeActiveSite(site));
if (site) {
dispatch(getAnalysers(site));
} else {
dispatch(clearSiteData(site));
}
};
const sites = [
{
ident: "",
name: "None",
},
].concat(sitess);
return (
<React.Fragment>
<FormControl className={classes.formControl}>
<InputLabel id="site-select-input-label">site</InputLabel>
<Select
id="site-select"
value={currentSiteId}
labelId="site-select-input-label"
onChange={(e) => handleChange(e)}
>
{sites.map((site) => {
return (
<MenuItem key={site.ident} value={site.ident}>
{site.name}
</MenuItem>
);
})}
</Select>
</FormControl>
</React.Fragment>
);
};
that component is in component B like this: <div > <A site={site} /> </div>
Let's imagine your MenuItem.js, specifically, its render() and constructor(). You'll want it to be able to be hidden/not-displayed, or visible/displayed. Use a state attribute for hidden to control this, your render will probably look like...
constructor(props) {
super(props);
this.state = {
'hidden':false,
};
}
render () {
if(this.state.hidden) {
return '';
}
return (
<div
onClick={(e) => this.handleOnClick(e)}
>
{this.props.value}
</div>
);
}
Notice I also added a handleOnClick(e) handler up above! That will simply call this.setState({'hidden':true}), so like...
handleOnClick(e) {
this.setState({'hidden':true});
}
I have an answer to a similar question elsewhere, if it might also help: How to set one component's state from another component in React

React PropTypes warning for function component with a prop that has a default value [duplicate]

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.

React: TypeError: Unable to get property 'handler' of undefined or null reference

I am new to React.js and cannot seem to get any event handlers to work. I get the above-referenced error anytime I make an event handler outside of the render function instead of as an annonymous inner class. Can someone point out what I'm doing wrong please?
class Checkboxes extends Component{
constructor(props) {
super(props);
this.state = { checked: [true, true],
frame: [values, values],
title: ['A', 'B'] };
this.handleChange= this.handleChange.bind(this);
}
handleChange(e) {
let index= e.target.id;
let newState = this.state.checked.slice();
newState[index] = !this.state.checked[index];
this.setState ({checked: newState});
}
render(){
const selectionBoxes = this.state.title.map(function(title, index) {
return (
<div className="w3-checkbox" id={index} onClick={this.handleChange}>
<input
type="checkbox"
label={'Division '+title}
value={this.state.checked[index]}
checked={!this.state.checked[index]}
onChange= {this.handleChange}
id={index} />
<label id={index} onClick={this.handleChange}>
{'Division '+ title}
</label>
</div>
);
});
const frameDisplay = this.state.frame.map(function(frame, index) {
return (
<div>
{this.state.checked[index]} ? null :
<DivFrame frameId={frame} width={this.state.width} height={this.state.height} title={this.state.title[index]} />
</div>
);
});
return (
{selectionBoxes}
);
}
};
export default Checkboxes;
It seems that, even though you may have bound the handleChange to this in the constructor, it is still not in scope within the this.state.title.map(function(title, index) {... function. I have fixed this problem by simply changing this.state.title.map(function(title, index) {... to this.state.title.map((title, index) => {...
This is the ES6 syntax and does the binding for me automatically.
Have a look here for a demo: https://codesandbox.io/s/py2zp8z1kj
Please note that for the sake of simplicity I have removed the code pertaining to the frames component since it's not really related to the problem and to cut down on the work required having to implement that component. To have the event handler working on that component as well though you will have to change the callback of the mapping function to the ES6 syntax as well.
Also, you will notice that in the return of the render() method, I have removed the curly braces because you do not need them since selectionBoxes is raw html and needs not to be evaluated. Actually evaluating it ({ selectionBoxes}) converts the value of selectionBoxes to an object which is NOT a valid react child. So rather put selectionBoxes as is in the render block.
In case you are not able to view the demo, this is how the code looks like:
class Checkboxes extends Component {
constructor(props) {
super(props);
this.state = {
checked: [true, true],
frame: [0, 1],
title: ['A', 'B']
};
}
handleChange(e) {
let index = e.target.id;
let newState = this.state.checked.slice();
newState[index] = !this.state.checked[index];
this.setState({ checked: newState });
}
render() {
const selectionBoxes = this.state.title.map( (title, index) => {
return (
<div className="w3-checkbox" id={index} onClick={this.handleChange}>
<input
type="checkbox"
label={'Division ' + title}
value={this.state.checked[index]}
checked={!this.state.checked[index]}
onChange={this.handleChange}
id={index} />
<label id={index} onClick={this.handleChange}>
{'Division ' + title}
</label>
</div>
);
});
return (
selectionBoxes
);
}
};
export default Checkboxes;

How to get "key" prop from React element (on change)?

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.

Categories

Resources