ReactJs, How can I add class name to Map of same divs - javascript

this is my code i'm trying to add a class on click to a clicked div but i have more than 1 div have the same classname so when i click to any
div the toggle class added to all divs not the one which i clicked what i want to know how can i specify the div which i want to add toggle class to it
Code:
const [isActive, setActive] = useState(false);
const toggleClass = () => {
setActive(!isActive)
console.log('sad')
}
return (
<div className="command_wrapper">
<div className="command_list">
{
Commands.map((item, index) => {
return (
<div className="command" >
<div className="command_face" onClick={toggleClass}>
<h1>{item.Command}</h1>
<p>{item.Description}</p>
</div>
<div className={isActive ? "command_body" : "disapper"}>
<div className="command_usage">
<h1>Usage</h1>
<p>{item.Usage}</p>
</div>
<div className="command_required">
<h1>Required Permissions</h1>
<p>{item.premissions}</p>
</div>
</div>
</div>
)
})
}
</div>
</div>
```

You can pass the item inside toggle function and verify if item passed is activated or just save the item clicked.
const [itemActive, setItemActive] = useState();
const toggleClass = (item) => {
setItemActive(item)
}
return (
<div className="command_wrapper">
<div className="command_list">
{
Commands.map((item, index) => {
return (
<div className="command" >
<div className="command_face" onClick={() => toggleClass(item)}>
<h1>{item.Command}</h1>
<p>{item.Description}</p>
</div>
<div className={item === itemActive ? "command_body" : "disapper"}>
<div className="command_usage">
<h1>Usage</h1>
<p>{item.Usage}</p>
</div>
<div className="command_required">
<h1>Required Permissions</h1>
<p>{item.premissions}</p>
</div>
</div>
</div>
)
})
}
</div>
</div>
```
If item has any unique property, you can save just then, like an ID or name. I think it will be better.

/*const [isActive, setActive] = useState(false);
const toggleClass = () => {
setActive(!isActive)
console.log('sad')
}*/
function handleClick(el){
//toggle the class which indicates selection ex. 'active'
el.classList.toggle('active');
//other stuff todo
}
return (
<div className="command_wrapper">
<div className="command_list">
{
Commands.map((item, index) => {
return (
<div className="command" >
//destruct event objet{event.target}
<div onClick={({target})=>handleClick(target)}>
<h1>{item.Command}</h1>
<p>{item.Description}</p>
</div>
....
...
</div>
)
})
}
</div>
</div>

Related

OnClick() handler in map function is changing the state of all elements instead of only clicked element

I am creating a Next js site mcqs and answer.
Initially only questions are rendered with the title and options.
There is a button to show the answer of given question but when button is clicked it is changing the state of all elements in the map function instead of element that is clicked.
export default function Chapter({ chapter }) {
const [right, setRight] = useState(false)
function handleOnClick() {
setRight(!right)
}
<main className='main_q'>
<h1>{chapter.items[0].name}</h1>
{chapter.items[0].questions.items.map((question, index) => {
return (
<div key={question.id} className='question_container'>
<div className='question_q_t'>
<div className='question_q'>Q</div>
<div className='question_t'>
<Markdown>{question.title}</Markdown>
</div>
</div>
<div className='option_container'>
<div className='option_a_o'>
<div className='option_a'>A</div>
<div className='option_o'>
<Markdown>{question.optionA}</Markdown>
</div>
</div>
<div className='option_a_o'>
<div className='option_a'>B</div>
<div className='option_o'>
<Markdown>{question.optionB}</Markdown>
</div>
</div>
<div className='option_a_o'>
<div className='option_a'>C</div>
<div className='option_o'>
<Markdown>{question.optionC}</Markdown>
</div>
</div>
<div className='option_a_o'>
<div className='option_a'>D</div>
<div className='option_o'>
<Markdown>{question.optionD}</Markdown>
</div>
</div>
</div>
<a
className='solution_link'
target='_blank'
href={`/${question.chapter.subject.category.slug}/${question.chapter.subject.slug}/${question.chapter.slug}/${question.id}`}
>
See Solution
</a>
<button onClick={handleOnClick}>Answer</button>
{right && <div>{question.rightAnswer}</div>}
</div>
)
})}
</main>
}
Put each question div into its own component, and make a right state in that component:
const Question = ({ question }) => {
const [right, setRight] = useState(false)
return (
<div key={question.id} className='question_container'>
// etc
Or make an array of right states in the parent:
export default function Chapter({ chapter }) {
const qs = chapter.items[0].questions.items;
const [rights, setRights] = useState(qs.map(q => false));
const makeHandleClick = (i) => {
setRights(
rights.map((r, j) => j === i ? r : !r)
);
};
// ...
<button onClick={makeHandleClick(i)}>Answer</button>
{rights[i] && <div>{question.rightAnswer}</div>}

React add active class to click element

I want add active class to click element but it is toogle. How can i fixed it?
const PodcastTab = () => {
const [tabOpened, setTabOpened] = useState(false);
return <div>
<div>
<span className={classNames('my-podcast',{'active':tabOpened})} onClick={()=>{setTabOpened(!tabOpened)}}>My Podcast</span>
<span className={classNames('podcasts-stats',{'active':!tabOpened})} onClick={()=>{setTabOpened(!tabOpened)}}>Podcast's Stats</span>
<div className="my-podcast-tab">
<Podcast />
</div>
<div className="podcasts-stats-tab">
<Podcast imgURL="https://i.picsum.photos/id/144/75/75.jpg?hmac=9kweqWXv0sL19dFj1CaMKxbH3kQMIuFFbHy2hWhKJ4w" status="x" title="y"/>
</div>
</div>
</div>;
}
You can use the following className:
className={classNames('podcasts-stats',{tabOpened ? 'active' : ''})}

React JS - custom accordion content won't slide open

Here's what I've have so far - Full working view https://codesandbox.io/s/hungry-elbakyan-v3h96
Accordion component:
const Accordion = ({ data }) => {
return (
<div className={"wrapper"}>
<ul className={"accordionList"}>
{data.map((item) => {
return (
<li className={"accordionListItem"} key={item.title}>
<AccordionItem {...item} />
</li>
);
})}
</ul>
</div>
);
};
const AccordionItem = ({ content, title }) => {
const [state, setState] = useState({
isOpened: false
});
return (
<div
className={cn("accordionItem", state.isOpened && "opened")}
onClick={() => setState({ isOpened: !state.isOpened })}
>
<div className={"lineItem"}>
<h3 className={"title"}>{title}</h3>
<span className={"icon"} />
</div>
<div className={"inner"}>
<div className={"content"}>
<p className={"paragraph"}>{content}</p>
</div>
</div>
</div>
);
};
When I click on the accordion item nothing happens. I can see the content appears in inspect and the state changes as expected but it doesn't slide down. Did I miss something in my css or component?
Here is what I was able to achieve. You may not like it completely(animations). But things seems sorted
https://codesandbox.io/s/relaxed-babbage-2zt4f?file=/src/styles.css
props name was not right for accordion body
and styles need to be changes once the accordion is in open state.
You need to add or remove the className inner when state.isOpen so you can see your content

Display/delete component on click

So, im trying to display my component named documentReader inside div with class desktop-app-grid by clicking and icon below, but icon is also a component, i tried doing this by using state, but i don't know how I can do this. I'm dropping my code below with hope someone can help me.
I got this:
<div className="desktop">
<div
className="desktop-app-grid"
>
</div>
<div className="taskbar">
<div className="taskbar-content">
<div className="apps">
<TaskbarAppIcon
appName="documentReader"
icon={icon}
title="My CV"
/>
</div>
<div className="status">
<Clock className="clock" />
</div>
</div>
</div>
</div>
);
}
And on click i want to get displayed in desktop-app-grid like this:
<div
className="desktop-app-grid"
>
<documentReader />
</div>
icon.js (code isn't complete)
class TaskbarAppIcon extends React.Component {
constructor() {
super();
this.state = {
clicked: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
const icon = document.querySelector("img");
icon.classList.toggle("icon-active");
setTimeout(() => {
icon.classList.toggle("icon-active");
}, 200);
this.setState({
clicked: true
});
}
render(){
const classes = this.props.appName + "Icon icon";
return (
<div className={classes} onClick={this.handleClick}>
<img src={this.props.icon} alt={this.props.appName} title={this.props.title} className="icon-image"></img>
<div className="isActive"></div>
</div>
);
}
}
export default TaskbarAppIcon;
is there any function that works like innerHTML, but isn't a dangerouslyInnerHTML?
what you need to do is move your handleClick and clicked state to the parent component where you rendering TaskbarAppIcon. Being more specific where you have this code:
<div className="desktop">
<div className="desktop-app-grid">
</div>
<div className="taskbar">
<div className="taskbar-content">
<div className="apps">
<TaskbarAppIcon
appName="documentReader"
icon={icon}
title="My CV"
/>
</div>
<div className="status">
<Clock className="clock" />
</div>
</div>
</div>
</div>
So for example, the above code is in you App component, so you need to let it like this:
class App extends React.Component {
constructor() {
super();
this.state = {
clicked: false,
};
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
const icon = document.querySelector("img");
icon.classList.toggle("icon-active");
setTimeout(() => {
icon.classList.toggle("icon-active");
}, 200);
this.setState({
clicked: !this.state.clicked,
});
};
render() {
return (
<div className="desktop">
<div className="desktop-app-grid">
// here's the trick, if your clicked state is TRUE it will show <documentReader />
{this.state.clicked && <documentReader />}
</div>
<div className="taskbar">
<div className="taskbar-content">
<div className="apps">
<TaskbarAppIcon
// Here you are specifying that TaskbarAppIcon has a prop handleClick and its a function
handleClick={this.handleClick}
appName="documentReader"
icon={icon}
title="My CV"
/>
</div>
</div>
</div>
</div>
);
}
}
And in your TaskbarAppIcon component you just need to change
<div className={classes} onClick={this.handleClick}>
to
<div className={classes} onClick={this.props.handleClick}>

Toggle between divs in React JSX

So I've got two input boxes that I want to be able to toggle (hide) between by clicking on them. They populate a table below them. I know it's not difficult but can't seem to make it happen easily.
It's all happening in the one component. Something like this:
<p id="toggle">
<span> Employer </span>
<span> Location </span>
</p>
<div id="left">..input box 1</div>
<div id="right">..input box 2</div>
What's the function I'd need to implement it? Thanks!
Your issue is indeed not very difficult.
Here is a solution with a function component:
const MyComponent = (props) => {
const [selected, setSelected] = useState(0)
return (
<div>
<p id="toggle">
<span onClick={() => setSelected(0)}> Employer </span>
<span onClick={() => setSelected(1)}> Location </span>
</p>
{(selected === 0) && <div id="left"> ..input box 1</div>}
{(selected === 1) && <div id="right"> ..input box 2</div>}
</div>
)
}
Here is a solution with a class component:
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
selected: 0
}
}
render() {
return (
<div>
<p id="toggle">
<span onClick={() => this.setState({ selected: 0 })}> Employer </span>
<span onClick={() => this.setState({ selected: 1 })}> Location </span>
</p>
{(selected === 0) && <div id="left"> ..input box 1</div>}
{(selected === 1) && <div id="right"> ..input box 2</div>}
</div>
)
}
}
If I'm understanding you're wanting to toggle the display of the div elemements on clicking the span elements (why not use anchors they're better suited). Below is a simple way to implement this,
(() =>
{
const togglers = document.querySelectorAll('#toggle span');
const togglees = document.querySelector('#toggle').parentNode.querySelectorAll('div');
togglers.forEach((toggler, index) =>
{
toggler.addEventListener('click', () =>
{
togglees.forEach(togglee => togglee.style.display = 'none');
togglees[index].style.display = 'block';
}, true);
});
})();
/* HIDE THOSE TOGGLEES BY DEFAULT CHANGE THIS!!!!!!!! */
div > div
{
display: none;
}
<div>
<p id="toggle">
<span> Employer </span>
<span> Location </span>
</p>
<div id="left"> ..input box 1</div>
<div id="right"> ..input box 2</div>
</div>

Categories