Can't get value of selected option - reactjs

I am trying to create a dashboard in react. I want to be able to select today, yesterday. this week. etc, and have data change. I am trying to do this by using:
<select onChange={handlefilter}>
{data.map((item) => (
<option value={item.id}>{item.tag}</option>
))}
</select>
where data =
let data = [
{id: 1, tag: "today" },
{id: 2, tag: "yesterday" },
{id: 3, tag: "this week" },
{id: 4, tag: "this month" },
{id: 5, tag: "all time" },
]
From here I wanted to use the handlefilter to find the id selected and then from there create conditions. The issue that I am having is that I can't get the value of the ids.
Full DashboardScreen.js
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { render } from "react-dom";
import Chart from 'react-google-charts';
import { summaryOrder } from '../actions/orderActions';
import LoadingBox from '../components/LoadingBox';
import MessageBox from '../components/MessageBox';
export default function DashboardScreen() {
const orderSummary = useSelector((state) => state.orderSummary);
const { loading, summary, error } = orderSummary;
const dispatch = useDispatch();
useEffect(() => {
dispatch(summaryOrder());
}, [dispatch]);
let order = [
{id: 1, tag: "today" },
{id: 2, tag: "yesterday" },
{id: 3, tag: "this week" },
{id: 4, tag: "this month" },
{id: 5, tag: "all time" },
]
const handleFilter = () => {
console.log(order.id)
}
return (
<div>
<div className="line">
</div>
<div className="background">
{loading ? (
<LoadingBox />
) : error ? (
<MessageBox variant="danger">{error}</MessageBox>
) : (
<>
<ul className="row summary">
<li>
<div className="summary-title color1">
<select onChange={handlefilter}>
{order.map((item) => (
<option value={item.id}>{item.tag}</option>
))}
</select>
</div>
</li>
<li>
<div className="summary-title color1">
<span>
<i className="fa fa-users" /> Users
</span>
</div>
<div className="summary-body">{summary.users[0].numUsers}</div>
</li>
<li>
<div className="summary-title color2">
<span>
<i className="fa fa-shopping-cart" /> Orders
</span>
</div>
<div className="summary-body">
{summary.orders[0] ? summary.orders[0].numOrders : 0}
</div>
</li>
<li>
<div className="summary-title color3">
<span>
<i className="fa fa-money" /> Sales
</span>
</div>
<div className="summary-body">
$
{summary.orders[0]
? summary.orders[0].totalSales.toFixed(2)
: 0}
</div>
</li>
</div>
<div>
</div>
</>
)}
</div>
</div>
);
}
I would really appreciate any help or advice on how to do this. Thank you!

You need to change select to :
<select onChange={handleFilter}>
Then update your handler to :
const handleFilter = (e) => {
console.log(e.target.value); // this is the order.id
}

Just update your function to as follows:
const handleFilter = (e) => {
console.log(e.target.value);
};
This will give you the id of selected element.

There are some problems with your code.
The main one is you are trying to read the id from order object, whereas you should read it from the event argument in handleFilter function.
The second is to always use key when you are mapping an array inside your render. So React can understand the difference.
And another optimization is to move your order array out of your component. Because it's not changing and you improve the performance with this little change.
The last thing is to let the React control the value of your form elements (input, select, etc.) for you. (Thanks John Detlefs for his comment)
So here is the optimal code for you:
import { useState } from "react";
const order = [
{ id: 1, tag: "today" },
{ id: 2, tag: "yesterday" },
{ id: 3, tag: "this week" },
{ id: 4, tag: "this month" },
{ id: 5, tag: "all time" }
];
export default function App() {
const [activeOption, setActiveOption] = useState();
const handleFilter = (event) => {
setActiveOption(event.target.value)
// console.log(event.target.value);
};
return (
<select value={activeOption} onChange={handleFilter}>
{order.map((item) => (
<option key={item.id} value={item.id}>
{item.tag}
</option>
))}
</select>
);
}

Related

How to add new property to an array of object through mapping in ReactJs

export default function App() {
const userData = [
{
id: 1,
name: "Gowtham",
followers: [
{ id: 11, name: "Anna" },
{ id: 12, name: "Theo" }
]
},
{
id: 2,
name: "Billy",
followers: [
{ id: 11, name: "Oliver" },
{ id: 12, name: "Emma" }
]
}
];
const [userToChat, setUserToChat] = useState("");
return (
<div className="App mt-5">
<h1>Message users followers</h1>
<select className="form-select" onChange={(e) => setUserToChat(e.target.value)}>
<option value="">Select</option>
<option value="Gowtham">Gowtham</option>
<option value="Billy">Billy</option>
</select>
{userData.map((user) => {
return (
{user.name === userToChat ? (
<div className="">
{user.followers.map((followers) => {
return (
<div className="d-flex">
<label className="col-form-label">{followers.name}</label>
<input type="text" name={followers.name} className="form-control-sm" />
</div>
);
})}
</div>
)
: ""
}
);
})}
</div>
);
}
Steps
First, I'm mapping through the userData object and checks the user name == chatToUser ("Gowtham").
If true, I map again to get the followers list of that selected user(Gowtham).
After I get the followers list(of Gowtham), I just want to add new property called message in followers object of userData and save the value that we get from the input field(Theo: "Hello, My man Theo") in the followers object in userData object.
Check this Images to see UI
![The UI Before selecting userToChat]
(https://i.stack.imgur.com/Q8Jny.png)
![The UI After selected User]
(https://i.stack.imgur.com/wz7JS.png)
example: the object should be like this after I enter values in input field.
{
id: 1,
name: "Gowtham",
followers: [
{ id: 11, name: "Anna", message: "Hi Anna"},
{ id: 12, name: "Theo", message: "Hello, My man Theo"}
]
}
I want to add new property called message in followers object of userData and save the value that we get from the input field(Theo: "Hello, My man Theo") in the followers object in userData object.
You'd need to manage the user data in state and then modify the state each time a message is updated.
Splitting your code into components can also help you more easily reason about the JSX.
Here's a code snippet demo:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.3/dist/css/bootstrap.min.css" />
<div id="root"></div><script src="https://cdn.jsdelivr.net/npm/react#18.2.0/umd/react.development.js"></script><script src="https://cdn.jsdelivr.net/npm/react-dom#18.2.0/umd/react-dom.development.js"></script><script src="https://cdn.jsdelivr.net/npm/#babel/standalone#7.20.15/babel.min.js"></script>
<script type="text/babel" data-type="module" data-presets="env,react">
// This Stack Overflow snippet demo uses UMD modules
const {StrictMode, useCallback, useState} = React;
const getInitialUserData = () => [{"id":1,"name":"Gowtham","followers":[{"id":11,"name":"Anna"},{"id":12,"name":"Theo"}]},{"id":2,"name":"Billy","followers":[{"id":11,"name":"Oliver"},{"id":12,"name":"Emma"}]}];
function Follower ({follower, updateFollowerMessage}) {
return (
<div className="d-flex">
<label className="col-form-label">{follower.name}</label>
<input
type="text"
name={follower.name}
className="form-control-sm"
onChange={ev => updateFollowerMessage(follower, ev.currentTarget.value)}
value={follower.message ?? ""}
/>
</div>
);
}
function App () {
const [users, setUsers] = useState(getInitialUserData);
const [activeUserIndex, setActiveUserIndex] = useState(-1);
const updateFollowerMessage = useCallback((
follower,
message,
) => setUsers(
users => users.map((u, i) => {
if (i !== activeUserIndex) return u;
const followers = u.followers.map(
f => f === follower ? {...f, message} : f
);
return {...u, followers};
})
), [activeUserIndex, setUsers]);
const user = users[activeUserIndex];
return (
<div className="App mt-5">
<h1>Message users followers</h1>
<select
className="form-select"
onChange={ev => setActiveUserIndex(Number(ev.currentTarget.value))}
>
<option value={-1}>Select</option>
{
users.map((user, index) => (
<option key={user.id} value={index}>{user.name}</option>
))
}
</select>
{
user ? (
<div className="">
{
user.followers.map(follower => (
<Follower
key={follower.id}
follower={follower}
updateFollowerMessage={updateFollowerMessage}
/>
))
}
</div>
) : null
}
</div>
);
}
const reactRoot = ReactDOM.createRoot(document.getElementById("root"));
reactRoot.render(
<StrictMode>
<App />
</StrictMode>
);
</script>

How to show only 10 items from the list of object in a dataset in Reacct

I want to display only 10 list items from the property name "text" which is in one of a dataset object and give more button below that. On this button click I want to show remaining list items. I tried with the below code using useState hook but not getting the desired result, I know I'm doing something wrong. Any help would be appreciated.
import React, { useState } from 'react';
const ReadMoreReadLess = ({ children }) => {
const [ReadMoreShown, setReadMoreShown] = useState(false);
const toggleBtn = () => {
setReadMoreShown(prevState => !prevState)
}
return (
<div className='readMore_readLess'>
{children}
<button onClick={toggleBtn}>Read More</button>
</div>
)
}
export default ReadMoreReadLess
Below is one of the dataset object
const data = [
{
type: "Names",
text: [
{id: "1", info: "Audi"},
{id: "2", info: "BMW"},
{id: "3", info: "Chevrolet"},
{id: "4", info: "Citroen"},
{id: "5", info: "Hyundai"},
{id: "6", info: "Mercedes-Benz"},
{id: "7", info: "Renault"},
{id: "8", info: "Seat"},
{id: "9", info: "KIA"},
{id: "10", info: "Toyota"},
],
image: service_1,
},];
I'm displaying like this.
<div className="services__service__description">
<ReadMoreReadLess>
{text.map((t) => (
<ul>
<li key={t.id}>
{t.info}
</li>
</ul>
))}
</ReadMoreReadLess>
</div>
this.state.current_page equals 0 initially then get changed when you want to show more items
<div className="services__service__description">
<ReadMoreReadLess>
{text.slice(0, (this.state.current_page+1)*10).map((t) => (
<ul>
<li key={t.id}>
{t.info}
</li>
</ul>
))}
</ReadMoreReadLess>
</div>
I did this changes to my code.
import React, { useState } from 'react';
const ReadMoreReadLess = ({ children }) => {
const [isReadMoreShown, setReadMoreShown] = useState(false);
const toggleBtn = () => {
setReadMoreShown((prevState) => !prevState)
}
return (
<div className='readMore_readLess'>
{isReadMoreShown ? children : children.slice(0, 5)}
<button onClick={toggleBtn}>Read More</button>
</div>
)
}
export default ReadMoreReadLess
Displaying it like this
<div className="services__service__description">
<ReadMoreReadLess>
{text.map((t) => (
<ul>
<li key={t.id}>
{t.info}
</li>
</ul>
))}
</ReadMoreReadLess>
</div>

Need help for loop in React

I'm learning React, JS and I'm trying to use the .map method to display some data in an array. For each element in the array I create a button to show/hide a description with css and I'm looking for a way to only show the description of one element instead of all descriptions. It is probably unclear but here is the code :
import "./styles.css";
import React, { useState } from "react";
export default function App() {
const [showDescription, setshowDescription] = useState(false);
const [anArray] = useState([
{ title: "First Div", description: "First description"},
{ title: "Antoher Div", description: "Another description"}
]);
return (
<div className="App">
{anArray.map((val, index) => {
return (
<div className="div" key={index}>
<div className="title">{val.title}</div>
<button className="btn" onClick={() => setshowDescription(!showDescription)}>
Show description
</button>
<div id={showDescription ? "display" : "hidden"}>
<div className="description">{val.description}</div>
</div>
</div>
);
})}
</div>
);
}
Do you have any idea please ?
Issue
You've a single boolean showDescription state that is toggling every description.
Solution
Store an index of the description you want to toggle. Use the index to match the currently mapped element. Conditionally render the description
export default function App() {
const [showId, setShowId] = useState(null);
// curried function to toggle to new index or back to null to hide
const toggleDescription = id => () => setShowId(showId => showId === id ? null : id);
const [anArray] = useState([
{ title: "First Div", description: "First description"},
{ title: "Antoher Div", description: "Another description"}
]);
return (
<div className="App">
{anArray.map((val, index) => {
return (
<div className="div" key={index}>
<div className="title">{val.title}</div>
<button className="btn" onClick={toggleDescription(index)}> // <-- pass index
Show description
</button>
{showId === index && ( // <-- check for index match
<div>
<div className="description">{val.description}</div>
</div>
)}
</div>
);
})}
</div>
);
}
You can use index to show/hide your div. The issue is you are using only one Boolean value to handle it.
export default function App() {
const [showDescriptionIndex, setshowDescriptionIndex] = useState(-1);
const [anArray] = useState([
{ title: "First Div", description: "First description"},
{ title: "Antoher Div", description: "Another description"}
]);
return (
<div className="App">
{anArray.map((val, index) => {
return (
<div className="div" key={index}>
<div className="title">{val.title}</div>
<button className="btn" onClick={() => setshowDescriptionIndex(index)}>
Show description
</button>
<div id={showDescriptionIndex === index ? "display" : "hidden"}>
<div className="description">{val.description}</div>
</div>
</div>
);
})}
</div>
);
}
Try It
import "./styles.css";
import React, { useState } from "react";
export default function App() {
const [showDescription, setshowDescription] = useState({});
const [anArray] = useState([
{ title: "First Div", description: "First description"},
{ title: "Antoher Div", description: "Another description"}
]);
return (
<div className="App">
{anArray.map((val, index) => {
return (
<div className="div" key={index}>
<div className="title">{val.title}</div>
<button className="btn" onClick={() => setshowDescription({...showDescription, [index]: !showDescription[index]})}>
Show description
</button>
<div id={showDescription && showDescription[index] ? "display" : "hidden"}>
{showDescription[index]}
<div className="description">{val.description}</div>
</div>
</div>
);
})}
</div>
);
}
Tip: Use class="show/hide" instead of id="show/hide"

style react component on click

so i have this simple divs of names:
i just want to press on one of them and get a background color of green and when pressing on another one the first one will be canceled so just one will be colored at a time. what i simply need is inline style or i don't know i'm stuck.
first.js:
import React from 'react';
function SidebarComponents({name,title,selected,onSelect}) {
const style={
cursor: "pointer"
};
const classes = {
selected: {
backgroundColor: '#00ff00'
}
}
return (
<div
name={name}
title = {title}
style={style}
>
{name}
</div>
)
}
export default SidebarComponents;
second.js:
import React, { useEffect, useState } from "react";
import SidebarComponents from "../SidebarComponents/SidebarComponents";
import 'bootstrap/dist/css/bootstrap.min.css';
import '../Sidebar1/Sidebar.css';
function Sidebar({ onChange }) {
const [selectedComponent, setSelectedComponent] = useState({
componentsName: [
{ name: "John Smith", title: "John Smith" },
{ name: "Male, 26 years old", title: "Gender and age" },
{ name: "john", title: "Alerts" },
{ name: "claude", title: "Recent" },
{ name: "edward", title: "Blood pressure" },
{ name: "mira", title: "Body weight" },
{ name: "alex", title: "Glucose" },
{ name: "zac", title: "SPO2" }
]
});
return (
<div>
{selectedComponent.componentsName.map(component => {
return (
<div className="row align-items-start sidebar-components">
<div className="col">
<SidebarComponents
name={component.name}
title={component.title}
/>
</div>
</div>
);
})}
</div>
);
}
export default Sidebar;
on Sidebar:
const [selectedName, setSelectedName] = useState(null);
//...
<SidebarComponents
name={component.name}
title={component.title}
selected={component.name === selectedName}
onSelect={setSelectedName}
/>
on SidebarComponents:
const selectedClassName = selected ? 'selected' : '';
//...
<div
name={name}
title={title}
style={style}
className={`sidebar ${selectedClassName}`} //you must add sidebar and selected classes to your styles
onClick={() => onSelect(name)}
>
{name}
</div>
Add key attribute to div, inside the map.
Handel onClick event, to store the selected element index/value in your state.
Apply style using conditional rendering of className.
second.js
<div>
{selectedComponent.componentsName.map((component, index) => {
return (
<div key={index} onClick={() => handelOnClick(index)} className="row align-items-start sidebar-components">
<div className="col">
<SidebarComponents
name={component.name}
title={component.title}
className={selectedIndex === index ? 'highlight' : ''}
/>
</div>
</div>
);
})}
</div>
As you are rendering text in first.js no need to use div wrapper, use 'p', 'span' tag
In second.js instead of iterating entire div block, use ul li

How to display a selected element from dropdown menu

I would like to display a certain RSS feed depending on what item you select from the dropdown menu. At the minute when I select the item it will display the link on the screen but it will not update the state.
import React, { Component } from 'react'
class FacebookRSSDropdown extends Component {
state = {
links: [{id: 1, name: "Lost and Found Pets Northern Ireland" , content: "https://www.facebook.com/PetsLostandFoundNorthernIreland/"},
{id: 2, name: "USPCA", content: "https://www.facebook.com/UlsterSPCA/"},
{id: 3, name: "Pawboost Northern Ireland", content: "https://www.facebook.com/Northern-Ireland-Lost-Dogs-Cats-Pets-147512902479398/"},
{id: 4, name: "Assisi Animal Sanctuary", content: "https://www.facebook.com/AssisiAnimalSanctuary/"},
{id: 5, name: "Pets Reunited Newry and Mourne", content: "https://www.facebook.com/PetsReunitedNewryAndMourne/"}
],
linkClicked: [{
content: ''
}]
}
handleChange = (e) => {
console.log(e.target.value);
this.setState({
linkClicked: e.target.value
})
}
render() {
return (
<div className="container-fluid">
<h1> Facebook RSS Feeds </h1>
<select className="form-control" onClick={this.handleChange}>
{this.state.links && this.state.links.map(link => {
return (
<option value={link.content}>{link.name}</option>
)
})}
</select>
<div id="rssfeeds" className="row">
<div className="col">
<div className="fb-page"
data-tabs="timeline,events,messages"
data-href={this.state.linkClicked.content}
data-width="500"
data-height="850"
data-hide-cover="false">
</div>
</div>
</div>
</div>
)
}
}
export default FacebookRSSDropdown
For a <select> you should register a listener for onChange rather than onClick
handleChange = ev => {
this.setState({
linkClicked: ev.target.value
})
}
<select className="form-control" onChange={this.handleChange}>

Resources