In react-js click a div that div will highlight and click again it will normal, we select multiple div and unselect, select maximum four div only these are the conditions. I beginner in react-js my div are ,
<div className='todoDiv select'>Task1</div>
<div className='todoDiv'>Task2</div>
<div className='todoDiv'>Task3</div>
<div className='todoDiv'>Task4</div>
<div className='todoDiv'>Task5</div>
here select class is used to highlight the div, how to solve this problem i have basic knowledge in react-js please help me
In react-js click a div that div will highlight and click again it will normal, we select multiple div and unselect, select maximum four div only these are the conditions. I beginner in react-js my div are ,
<div className='todoDiv select'>Task1</div>
<div className='todoDiv'>Task2</div>
<div className='todoDiv'>Task3</div>
<div className='todoDiv'>Task4</div>
<div className='todoDiv'>Task5</div>
here select class is used to highlight the div, how to solve this problem i have basic knowledge in react-js please help me
Share Improve this question asked Jun 12, 2022 at 17:51 manoop mmanoop m 672 silver badges13 bronze badges 1- To be clear, you are saying that you want to only allow the user to click on 4 options max at a time? What are you expecting to happen if they click 5? – LTFoReal Commented Jun 12, 2022 at 18:13
5 Answers
Reset to default 3I'd approach this by storing an array of todo objects in state with useState()
, and maintain a selected
property for each todo. As the todos are clicked, the selected property is changed.
To limit the selections to 4, simply add a check with a count like below.
CodeSandbox demo
import React, { useState } from "react";
import ReactDOM from "react-dom";
function App() {
const [todos, setTodos] = useState([
{ id: "1", name: "Task 1", selected: true },
{ id: "2", name: "Task 2", selected: false },
{ id: "3", name: "Task 3", selected: false },
{ id: "4", name: "Task 4", selected: false },
{ id: "5", name: "Task 5", selected: false }
]);
const todoClicked = (e) => {
// max 4 selected
if (!e.target.classList.contains("selected")) {
const selectedCount = todos.filter((todo) => todo.selected).length;
if (selectedCount === 4) {
return;
}
}
setTodos(
todos.map((todo) =>
todo.id === e.target.getAttribute("data-id")
? { ...todo, selected: !todo.selected }
: todo
)
);
};
return (
<div>
{todos.map((todo) => (
<div
onClick={todoClicked}
data-id={todo.id}
key={todo.id}
className={`todoDiv${todo.selected ? " selected" : ""}`}
>
{todo.name}
</div>
))}
</div>
);
}
ReactDOM.render(<App />, document.getElementById("container"));
In Reactjs, we use state to keep track of and render the view of the ponent. In your case, we can create a state called selected which maintains the list of selected tasks.
import React, {useState, useEffect} from 'react';
import './App.css';
function App() {
const [selected, setSelected] = useState([])
const updateSelected = (task) => {
if(!selected.includes(task) && selected.length < 4) {
let newSelected = [...selected, task];
setSelected(newSelected)
} else {
let newSelected = selected.filter(t => t !== task)
setSelected(newSelected)
}
}
let tasks = ["Task1", "Task2", "Task3", "Task4", "Task5"]
return (
<main>
{
tasks.map(task => (
<div onClick={() => updateSelected(task)} className={`todoDiv ${selected.includes(task) ? 'select' : ''}`}>{task}</div>
))
}
{`selected = ${selected.join(", ")}`}
</main>
);
}
export default App;
Initally, it is empty. When the user clicks on a task, it is added to the list of selected tasks. In the updateSelected, we implement required logic as shown above. Notice in the className for each task we use JaveScript template strings. This helps us to conditionally add class 'selected' to the className if it is selected by the user.
I have added a TASK_LIST
to dynamically render the div. Here toggleTask
function will both select & de-select the div. And as you said, maximum of four div will be selected.
import { Fragment, useState } from "react";
const TASK_LIST = [1, 2, 3, 4, 5];
export default function MultiSelect() {
const [selectedTask, selectTask] = useState([]);
const isSelected = (taskId) => {
return selectedTask.filter((task) => task === taskId).length;
};
const toggleTask = (taskId) => {
if (isSelected(taskId)) {
// deselect div
selectTask((tasks) => tasks.filter((ts) => ts !== taskId));
} else if (selectedTask.length < 4) {
// select div, max four div will be selected
selectTask((tasks) => [...tasks, taskId]);
}
};
return (
<Fragment>
{TASK_LIST.map((task) => (
<div
className={`todoDiv${isSelected(task) ? " select" : ""}`}
key={task}
onClick={() => toggleTask(task)}
>
Task{task}
</div>
))}
</Fragment>
);
}
/* Start by defiinig a variable 'divState' to save the state of
your divs and a function 'setDivState' sto modify that state.
The state variable 'divState' eventually will look like this:
{
div1: false,
div2: true,
div3: false,
...
}
*/
const [divState, setDivState] = useState({})
// we will use this function to update a div state:
const updateState = (id) => {
setDivState(prevState =>
({
...prevState, // keep the other divs as they are rught now
[`div${item}`]: !prevState[`div${item}`] // update the current
// div's
// state
}))
}
// Now we will render the divs, as many as you want
// I will use a the map function to iterate over an array of 4 divs
{
[1, 2, 3, 4].map(item => (
<div
className={`todoDiv ${divState[`div${item}`] ? 'select' : ''}`} // assign
// class dynamically depending on the current div's state
onClick={() => updateState(item)}>
{/* render something inside the divs */}
</div>
))
}
A plete ponent example:
import React, {useState} from 'react';
const YourComponent = () => {
/* Start by defiinig a variable 'divState' to save the state of
your divs and a function 'setDivState' sto modify that state.
The state variable 'divState' eventually will look like this:
{
div1: false,
div2: true,
div3: false,
...
}
*/
const [divState, setDivState] = useState({})
// we will use this function to update a div state:
const updateState = (id) => {
setDivState(prevState =>
({
...prevState, // keep the other divs as they are rught now
[`div${item}`]: !prevState[`div${item}`] // update the current
// div's
// state
}))
}
// Now we will render the divs, as many as you want
// I will use a the map function to iterate over an array of 4 divs
return (
<> {
[1, 2, 3, 4].map(item => (
<div
{/* assign class dynamically depending on the current
div's state */}
className={`todoDiv ${divState[`div${item}`] ? 'select' : ''}`}
onClick={() => updateState(item)}>
{/* render something inside the divs */}
</div>
))
}
</>
)
}
you can put styles in a variable like so
const [style, setStyle] = useState({ "--my-css-var": 10 })
Then put this in your div like so
<div style={style}>...</div>
Then, create a function onClick on the div that changes the "style" variable. Change the state of the the style variable
<div style={style} onClick={() => setStyle({"--my-css-var": 12})}>...</div>
You get the jist