I'm using functional component in react js , my onClick function triggers with component rendering without click on my li element ;
this is my parent component that passed the handleCallDetails function as props to child component:
export default function Cartable(){
const [items , setItems] = useState(null);
const [details , setDetails] = useState(null);
function handleCallDetails(id){
if(items !== null && details === null){
let d = items.find(x => {
return x.id === id;
});
}
}
useEffect(() => {
axios.get(`/workflows/${mode}` ,{
params : {
OrganizationId : "FE905B40-DA6E-4A81-8A4F-B447AA6B0EA3" ,
Type : 2 ,
sortorder : "desc" ,
pageIndedx : 1 ,
pageSize : 10
}
}).then(response => {
// console.log('response : ***************** ' , response);
setItems(response.data.data);
}).catch(error => {
console.log('error : ****************** ' , error);
});
} , [mode]);
return (
<Grid container spacing={2}>
<Grid item xs={12} sm={4} md={3}>
<div className="drt_RightSide drt_segment">
<h4 className="drt_RightSideTitle">
<i className="far fa-inbox"></i>
کارتابل
</h4>
<ul>
{/* <li>
<i class="far fa-inbox"></i>
<span>درخواست ها</span>
</li> */}
<li onClick={() => {setMode('pending');}}>
<i className="fas fa-exclamation"></i>
<span><FormattedMessage id="CARTABLE_PENDING" /></span>
<span className="drt_badge_warning drt_NotifNum">5</span>
</li>
<li onClick={() => {setMode('approved');}}>
<i className="far fa-check"></i>
<span>تایید شده</span>
</li>
<li onClick={() => {setMode('rejected');}}>
<i className="far fa-times"></i>
<span>رد شده</span>
<span className="drt_badge_error drt_NotifNum">7</span>
</li>
<li>
<i className="far fa-bell"></i>
<span>خارج از فرآیند</span>
</li>
</ul>
</div>
</Grid>
<Grid item xs={12} sm={8} md={9}>
<div className="drt_LeftSide drt_segment"> */}
{/* cartbale list */}
<CartableList
items={items}
callDetails={handleCallDetails}/>
</div>
</Grid>
</Grid>
);
}
and it is my child compnent that use onClick function that named callDetails:
export default function CartableList(props){
const [showbox , setShowbox] = useState(false);
const [age, setAge] = useState('');
const handleChange = (event) => {
setAge(event.target.value);
};
function handleFilterBox(){
setShowbox(!showbox);
}
return (
<Fragment>
{/* cartable list */}
<div style={{direction : "ltr"}}>
<Scrollbars style={{ height: 400 }}>
{
props.items && props.items !== undefined ?
props.items.map(function(item , index){
return (
<div className="drt_clearfix drt_CartableItem" key={index} onClick={(props.callDetails)(item.id)}>
{/* <div className={clsx(drt_ItemStar , item.star ? drt_IsStared : '')}>
<span><i className={clsx(item.star ? "fas fa-star" : "fal fa-star")}></i></span>
</div> */}
<div className="drt_ItemImg">
<span>
<img alt={userImg} src={item.pictureUrl !== undefined && item.pictureUrl !== null ? item.image : userImg} />
</span>
</div>
<div className={clsx("drt_ItemName" , !item.isSeen ? "drt_IsNotSeen" : '')}>
{item.issuerFirstName}
<br />
{item.issuerLastname}
</div>
<div className="drt_ItemIcon">
<Tooltip title={(props.moduleType)(item.type).name}>
<span className={item.isSeen ? "drt_badge_default" : "drt_badge_primary"}>
<i className={(props.moduleType)(item.type).icon} />
</span>
</Tooltip>
</div>
<div className={clsx("drt_ItemDesc" , !item.isSeen ? "drt_IsNotSeen" : '')}>
{item.objectTitle}
</div>
<div className="drt_ItemStatus">
<span className={(props.stateClass)(item.status)}>
{(props.stateTitle)(item.status)}
</span>
</div>
<div className={clsx("drt_ItemDate" , !item.isSeen ? "drt_IsNotSeen" : '')}>
<p>
<span>
{item.issuerTime}
</span>
<span>
{item.issuerDate}
</span>
</p>
<i className="fal fa-clock" />
</div>
</div>
);
}) : ''
}
</Scrollbars>
</div>
</Fragment>
);
}
please help me to solve this problem without convert my functional component to class component and binding my function
The correct way is this. You need to use arrow function or else react will understand that you want to execute the function at load
wrong
<div className="drt_clearfix drt_CartableItem" key={index} onClick={(props.callDetails)(item.id)}>
correct
<div className="drt_clearfix drt_CartableItem" key={index} onClick={() => props.callDetails(item.id)}>
Change from
onClick={() => {setMode('rejected');}}
to
onClick={() => setMode('rejected')}
Also
<div className="drt_clearfix drt_CartableItem" key={index} onClick={() => props.callDetails(item.id)}>
But where did you define the const [mode, setMode] state
It seems you exec your callback function immediately as it renders based on your code:
onClick={(props.callDetails)(item.id)}
It's supposed to be:
onClick={() => props.callDetails(item.id)}
Is that the issue?
It's mainly because of piece of code onClick={(props.callDetails)(item.id)} in your child component. This code is actually executing callDetails function and passing the item.id value immediately. One way to handle this is to wrap your function.
onClick={() => {props.callDetails(item.id)}}
A simple reason as to why onClick is not called when it is wrapped is because it is not directly passing in any value when initialised.
Related
I want to add a border when the class is "transporation active" but when I click one of the icons, all of them become active. I want only the clicked one to become active. This is for selecting categories. My react code is like this:
const [transportationClick, setTransportationClick] = useState(false);
const handleTransportationClick = () => setTransportationClick(!transportationClick);
/* where I use it */
<div className="transportation-types">
<div className={transportationClick ? "transportation active" : "transportation"} onClick={handleTransportationClick}>
<div className="transportation-icon">
<FaCar />
</div>
</div>
<div className={transportationClick ? "transportation active" : "transportation"} onClick={handleTransportationClick}>
<div className="transportation-icon">
<FaBus />
</div>
</div>
<div className={transportationClick ? "transportation active" : "transportation"} onClick={handleTransportationClick}>
<div className="transportation-icon">
<FaWalking />
</div>
</div>
</div>
The issue is that all the icons share the same state, which results in all of the icons becoming active when one of them is clicked. There are several ways to solve this - you can refactor each icon into it's own component:
const Icon = ({ icon }) => {
const [transportationClick, setTransportationClick] = useState(false);
const handleTransportationClick = () => setTransportationClick(!transportationClick);
return (
<div className={transportationClick ? "transportation active" : "transportation"} onClick={handleTransportationClick}>
<div className="transportation-icon">
{icon}
</div>
</div>
)
}
const Parent = () => {
return (
<div className="transportation-types">
<Icon icon={<FaCar />} />
<Icon icon={<FaBus />} />
<Icon icon={<FaWalking />} />
</div>
)
}
Or set the state to an index corresponding to the order your showing the icon in:
const Parent = () => {
const [transportationClick, setTransportationClick] = useState(0)
return (
<div className="transportation-types">
<div
className={transportationClick === 0 ? 'transportation active' : 'transportation'}
onClick={() => setTransportationClick(0)}
>
<div className="transportation-icon">
<FaCar />
</div>
</div>
<div
className={transportationClick === 1 ? 'transportation active' : 'transportation'}
onClick={() => setTransportationClick(1)}
>
<div className="transportation-icon">
<FaBus />
</div>
</div>
<div
className={transportationClick === 2 ? 'transportation active' : 'transportation'}
onClick={() => setTransportationClick(2)}
>
<div className="transportation-icon">
<FaWalking />
</div>
</div>
</div>
)
}
I would like to change the background color from the DIV when I click without affecting other buttons in the same line. I hope you could help me.. THank you!
For example when I click on the first DIV Developers, the background color change, however, it affects the other buttons, I want to affect only the button I click to change the background color.
import React, { useState } from 'react';
import './navbar.css';
import Logo from '../../assets/img/ubuntu.jpg'
import { Dropdown } from '../ui/dropdown/Dropdown';
export const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const [style, setStyle] = useState(true);
const [styleIcon, setStyleIcon] = useState(true);
const [isActive, setIsActive] = useState(false);
const handleClick = () => {
setIsActive(current => !current);
setIsOpen(!isOpen);
};
const toggling = () => {
setIsOpen(!isOpen);
changeStyle();
changeStyleIcon();
};
const changeStyle = () => {
setStyle(!style);
};
const changeStyleIcon = () => {
setStyleIcon(!styleIcon);
};
return (
<>
<div className="div_main_navbar">
<div className="div_main_title">
<div className="div_main_button">
<img className="img_logo" src={Logo} alt="logo" />
</div>
<div
style={{
backgroundColor: isActive ? 'salmon' : '',
color: isActive ? 'white' : '',
}}
onClick={handleClick}
>
<strong className="label_strong">Enterprise</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div
style={{
backgroundColor: isActive ? 'salmon' : '',
color: isActive ? 'white' : '',
}}
onClick={handleClick}
>
<strong className="label_strong">Developer</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div className={style ? 'div_main_button' : 'div_main_button_change_color'} onClick={toggling}>
<strong className="label_strong">Community</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div className={style ? 'div_main_button' : 'div_main_button_change_color'} onClick={toggling}>
<strong className="label_strong">Download</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
</div>
<div className="div_main_search_signin">
<div className="div_main_se_in">
<strong className="label_strong">Search</strong>
</div>
<div className="div_main_se_in">
<strong className="label_strong">Sign in</strong>
</div>
</div>
</div>
{
isOpen && (
<Dropdown/>
)
}
</>
)
}
You should have a number state instead of a boolean state for isActive
const [isActive, setIsActive] = useState(); //leave it empty as no active buttons initially
And then you should have another constant variable for restrict button state values
const BUTTONS = {
enterprise: 1,
developer: 2,
}
Modify handleClick accordingly
const handleClick = (buttonId) => {
setIsActive(buttonId);
setIsOpen(!isOpen);
};
The last part is integrating button ids with your div elements and adding conditional renderings based on isActive value
<div
style={{
backgroundColor: isActive === BUTTONS.enterprise ? 'salmon' : '',
color: isActive === BUTTONS.enterprise ? 'white' : '',
}}
onClick={() => handleClick(BUTTONS.enterprise)}
>
<strong className="label_strong">Enterprise</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div
style={{
backgroundColor: isActive === BUTTONS.developer ? 'salmon' : '',
color: isActive === BUTTONS.developer ? 'white' : '',
}}
onClick={() => handleClick(BUTTONS.developer)}
>
<strong className="label_strong">Developer</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
The full possible modification
import React, { useState } from 'react';
import './navbar.css';
import Logo from '../../assets/img/ubuntu.jpg'
import { Dropdown } from '../ui/dropdown/Dropdown';
const BUTTONS = {
enterprise: 1,
developer: 2,
}
export const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const [style, setStyle] = useState(true);
const [styleIcon, setStyleIcon] = useState(true);
const [isActive, setIsActive] = useState(); //leave it empty as no active buttons initially
const handleClick = (buttonId) => {
setIsActive(buttonId);
setIsOpen(!isOpen);
};
const toggling = () => {
setIsOpen(!isOpen);
changeStyle();
changeStyleIcon();
};
const changeStyle = () => {
setStyle(!style);
};
const changeStyleIcon = () => {
setStyleIcon(!styleIcon);
};
return (
<>
<div className="div_main_navbar">
<div className="div_main_title">
<div className="div_main_button">
<img className="img_logo" src={Logo} alt="logo" />
</div>
<div
style={{
backgroundColor: isActive === BUTTONS.enterprise ? 'salmon' : '',
color: isActive === BUTTONS.enterprise ? 'white' : '',
}}
onClick={() => handleClick(BUTTONS.enterprise)}
>
<strong className="label_strong">Enterprise</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div
style={{
backgroundColor: isActive === BUTTONS.developer ? 'salmon' : '',
color: isActive === BUTTONS.developer ? 'white' : '',
}}
onClick={() => handleClick(BUTTONS.developer)}
>
<strong className="label_strong">Developer</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div className={style ? 'div_main_button' : 'div_main_button_change_color'} onClick={toggling}>
<strong className="label_strong">Community</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div className={style ? 'div_main_button' : 'div_main_button_change_color'} onClick={toggling}>
<strong className="label_strong">Download</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
</div>
<div className="div_main_search_signin">
<div className="div_main_se_in">
<strong className="label_strong">Search</strong>
</div>
<div className="div_main_se_in">
<strong className="label_strong">Sign in</strong>
</div>
</div>
</div>
{
isOpen && (
<Dropdown/>
)
}
</>
)
}
So what I have done is isolate the clicked state of the div within a separate functional component. This way one click would not affect the other.
You can define this component as
// please provide appropriate component name
const HandleClickDiv = ({ heading, styleIcon, isOpen, setIsOpen }) => {
const [clicked, setClicked] = useState(false);
const onClick = () => {
setClicked(!clicked);
setIsOpen(!isOpen);
};
return (
<div
style={{
backgroundColor: clicked ? 'salmon' : '',
color: clicked ? 'white' : '',
}}
onClick={onClick}
>
<strong className="label_strong">{heading}</strong>
<div className="div_icon">
<i
className={
styleIcon ? 'fa-solid fa-angle-down' : 'fa-solid fa-angle-up'
}
></i>
</div>
</div>
);
};
The component is called as :
{
handleClickHeadings.map((heading) => {
return (
<HandleClickDiv
heading={heading}
styleIcon={styleIcon}
isOpen={isOpen}
setIsOpen={setIsOpen}
/>
);
});
}
Following is the rest of your code
import React, { useState } from 'react';
import './navbar.css';
import Logo from '../../assets/img/ubuntu.jpg';
import { Dropdown } from '../ui/dropdown/Dropdown';
export const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const [style, setStyle] = useState(true);
const [styleIcon, setStyleIcon] = useState(true);
const toggling = () => {
setIsOpen(!isOpen);
changeStyle();
changeStyleIcon();
};
const changeStyle = () => {
setStyle(!style);
};
const changeStyleIcon = () => {
setStyleIcon(!styleIcon);
};
const handleClickHeadings = ['Enterprise', 'Developer'];
return (
<>
<div className="div_main_navbar">
<div className="div_main_title">
<div className="div_main_button">
<img className="img_logo" src={Logo} alt="logo" />
</div>
{handleClickHeadings.map((heading) => {
return (
<HandleClickDiv
heading={heading}
styleIcon={styleIcon}
isOpen={isOpen}
setIsOpen={setIsOpen}
/>
);
})}
<div
className={
style ? 'div_main_button' : 'div_main_button_change_color'
}
onClick={toggling}
>
<strong className="label_strong">Community</strong>
<div className="div_icon">
<i
className={
styleIcon ? 'fa-solid fa-angle-down' : 'fa-solid fa-angle-up'
}
></i>
</div>
</div>
<div
className={
style ? 'div_main_button' : 'div_main_button_change_color'
}
onClick={toggling}
>
<strong className="label_strong">Download</strong>
<div className="div_icon">
<i
className={
styleIcon ? 'fa-solid fa-angle-down' : 'fa-solid fa-angle-up'
}
></i>
</div>
</div>
</div>
<div className="div_main_search_signin">
<div className="div_main_se_in">
<strong className="label_strong">Search</strong>
</div>
<div className="div_main_se_in">
<strong className="label_strong">Sign in</strong>
</div>
</div>
</div>
{isOpen && <Dropdown />}
</>
);
};
Note: the array of headings const handleClickHeadings = ['Enterprise', 'Developer']; allows you to loop through them and render the same div with different heading. This is possible for these 2 divs since everything else in them was exactly the same
This code:
How to display a dialog when a button is clicked using react and typescript?
I wanna open dialog from each todos, how to make it ? I used react js and typescript. Help me to resolve this problem.
interface ListProps {
todos: INote[];
onDelete: (title: string) => void;
}
const TodoList: React.FunctionComponent<ListProps> = ({ todos, onDelete }) => {
const [showAlert, setShowAlert] = useState(false);
const [todo, setTodos] = useState(null);
How to select each item by ts?It doesn't work. What is reason? Thanks!
const handleOpenDialog = (todos: any) => {
setTodos(todos);
setShowAlert(true);
};
const handleCloseDialog = () => {
setShowAlert(false);
};
return (
<>
<section className="list list--wrapper">
{todos.map((todos) => (
<div className="item list__item" key={todos.title}>
<span className="item__title">{todos.title}</span>
<div className="item__group">
<input
className="item__completed"
type="checkbox"
checked={todos.completed}
/>
<span className="item__decs">{todos.desc}</span>
</div>
<div className="item__btn">
<button
className="item__btnd"
onClick={() => handleOpenDialog(todos)}
>
Delete
</button>
<button className="item__btne">Edit</button>
</div>
{showAlert && todo && (
<AlertDialog
handleCloseDialog={handleCloseDialog}
title={todos.title}
/>
)}
</div>
))}
</section>
</>
);
};
export default TodoList;
just add a condition to only show the AlertDialog on selected todos
<section className="list list--wrapper">
{todos.map((todos) => (
<div className="item list__item" key={todos.title}>
<span className="item__title">{todos.title}</span>
<div className="item__group">
<input
className="item__completed"
type="checkbox"
checked={todos.completed}
/>
<span className="item__decs">{todos.desc}</span>
</div>
<div className="item__btn">
<button
className="item__btnd"
onClick={() => handleOpenDialog(todos)}
>
Delete
</button>
<button className="item__btne">Edit</button>
</div>
{showAlert && todos.title===todo?.title && (
<AlertDialog
handleCloseDialog={handleCloseDialog}
title={todos.title}
/>
)}
</div>
))}
</section>
or just move the AlertDialog outside the map
<section className="list list--wrapper">
{todos.map((todos) => (
<div className="item list__item" key={todos.title}>
<span className="item__title">{todos.title}</span>
<div className="item__group">
<input
className="item__completed"
type="checkbox"
checked={todos.completed}
/>
<span className="item__decs">{todos.desc}</span>
</div>
<div className="item__btn">
<button
className="item__btnd"
onClick={() => handleOpenDialog(todos)}
>
Delete
</button>
<button className="item__btne">Edit</button>
</div>
</div>
))}
{showAlert && todo && (
<AlertDialog
handleCloseDialog={handleCloseDialog}
title={todos.title}
/>
)}
</section>
I am in the process of making a comment system like the one on youtube. In my implementation, when I click on modify, all comments are now inputs but only the value of the selected input will be modified. how to trigger only the element i clicked.
as you can see it triggers all the array elements
function App() {
const [open, setOpen] = useState(false);
return (
<div className="container mt-5">
<MDBRow>
{data &&
data.map((item) => (
<MDBCol md="7" lg="7" key={item.id} className="mb-4">
{!open && (
<>
<div className="font-weight-bolder float-left pr-2">
{item.name}
</div>
<div className="float-right pr-2">
<button
onClick={() => {
setOpen(true);
}}
>
Modifier
</button>
</div>
</>
)}
{open && (
<UpdateData
id={item.id}
name={item.name}
onAbort={() => setOpen(false)}
submit={() => setOpen(false)}
/>
)}
</MDBCol>
))}
</MDBRow>
</div>
);
}
export const UpdateData = ({ name, id, onAbort, submit }) => {
const formik = useFormik({
initialValues: {
id: id,
name: name,
},
onSubmit: async (values) => {
console.log(values);
submit();
},
});
return (
<form onSubmit={formik.handleSubmit}>
<MDBInput
value={formik.values.name}
name="name"
onChange={formik.handleChange}
/>
<div className="float-right">
<span onClick={onAbort} className="text-capitalize grey-text">
Cancel
</span>
<button type="submit">confirm</button>
</div>
</form>
);
};
And this is the sandbox
that i have created
To trigger only one element to be clicked you have to pass the index
function App() {
const [open, setOpen] = useState(false);
const [selectedRow, setSelectedRow] = useState(undefined);
const onSelectedRow = (index) => {
setSelectedRow(index);
setOpen(true);
}
return (
<div className="container mt-5">
<MDBRow>
{data &&
// here you will get the index
data.map((item,index) => (
<MDBCol md="7" lg="7" key={item.id} className="mb-4">
{!open && (
<>
<div className="font-weight-bolder float-left pr-2">
{item.name}
</div>
<div className="float-right pr-2">
// Now onClick pass the index of selected row to onSelectedRow
<button
onClick={() =>onSelectedRow(index)}
>
Modifier
</button>
</div>
</>
)}
// here add condition to open selected row
{ (open === true && selectedRow === index) ? (
<UpdateData
id={item.id}
name={item.name}
onAbort={() => setOpen(false)}
submit={() => setOpen(false)}
/>
) : null
}
</MDBCol>
))}
</MDBRow>
</div>
);
}
Sandbox code https://codesandbox.io/s/youthful-wave-k4eih?file=/src/App.js
If you have any queries comment below!
instead of having a false default value in your hook you should have a unique key for each element. By default, it applies to all elements.
I am wanting to hide other sibling divs (dropdowns in my case) when I click the statusPillDropdown
so far I click I am setting the status to true and opening the div,
{DropDown ${toggleStatusDropdown ? "open": ""}}
Do I just need to set the state to false for previously opened ones? Not sure how to do this.
thank you
import React, { useState } from "react";
import "./StatusPillDropdown.scss";
function StatusPillDropdown({
cellData,
rowItemId,
onStatusPillDropdownChange
}) {
const [toggleStatusDropdown, setToggleStatusDropdown] = useState();
const toggleDropdown = (action, rowItemId, e) => {
if (action === "pillClick") {
setToggleStatusDropdown(true);
} else {
onStatusPillDropdownChange(rowItemId, e.target.getAttribute("value"));
setToggleStatusDropdown(false);
}
};
const renderstatusPillDropdown = (cellData, rowItemId) => (
<React.Fragment>
<span
className="statusPillDropdown"
onClick={() => toggleDropdown("pillClick", rowItemId)}
>
<span className={`status-pill ${cellData.type}`}>{cellData.text}</span>
</span>
<div className="status">
<div className="dropdown-container">
<div className={`DropDown ${toggleStatusDropdown ? "open" : ""}`}>
<ul>
<li
value="Information only"
onClick={e => toggleDropdown("liClick", rowItemId, e)}
>
<span></span>Information only
</li>
<li
value="Unresolved"
onClick={e => toggleDropdown("liClick", rowItemId, e)}
>
<span className="unresolved"></span>Unresolved
</li>
<li
value="Partially Resolved"
onClick={e => toggleDropdown("liClick", rowItemId, e)}
>
<span className="partyResolved"></span>Partially Resolved
</li>
<li
value="Fully Resolved"
onClick={e => toggleDropdown("liClick", rowItemId, e)}
>
<span className="resolved"></span>Fully Resolved
</li>
</ul>
</div>
</div>
</div>
</React.Fragment>
);
return (
<React.Fragment>
{renderstatusPillDropdown(cellData, rowItemId)}
</React.Fragment>
);
}
export default StatusPillDropdown;