toggle class div elements in react.js - reactjs

Hi I am newbie in Reactjs.
I am trying to make each different toggle div classes when click buttons.
import React from 'react';
class Home extends React.Component{
state = { isActive: false };
handleToggle = () => {
this.setState({ isActive: !this.state.isActive });
};
render(){
const isActive = this.state.isActive;
return (
<>
<button onClick={this.handleToggle} className={isActive ? "btn1" : "btn-on1"}>Toggle class1</button>
<div className={isActive ? "box1" : "box-active1"}>11</div>
<br />
<button onClick={this.handleToggle} className={isActive ? "btn2" : "btn-on2"}>Toggle class2</button>
<div className={isActive ? "box2" : "box-active2"}>22</div>
</>
)
}
}
export default Home;
The problem is when click button, both button toggle together at same time.
I want to make them each button toggle only itself.
How do I fix it ?

I think you could achieve this by changing the state from boolean so it can refer to a specific div:
state = { isActive: '' };
handleToggle = (btn) => {
this.setState({ isActive: btn });
};
render(){
const isActive = this.state.isActive;
return (
<>
<button onClick={() => this.handleToggle('button1')} className={isActive === 'button1' ? "btn1" : "btn-on1"}>Toggle class1</button>
<div className={isActive === 'button1' ? "box1" : "box-active1"}>11</div>
<br />
<button onClick={() => this.handleToggle('button2')} className={isActive === 'button2' ? "btn2" : "btn-on2"}>Toggle class2</button>
<div className={isActive === 'button2' ? "box2" : "box-active2"}>22</div>
</>
)
}

Related

How to only select one button at a time with React? Without radio buttons

I am trying to write a quiz type module where you can select one of two answers.
const [active, setActive] = useState(true);
const toggle = () => {
setSelected(!selected)
}
<div id="quizAnswers">
<div className="answer {active ? 'active' : ''}">
{quiz.answers[0].text}
<button label="{active ? 'ACTIVE' : 'inactive'}" onClick={toggle}>
{active ? "ACTIVE" : "inactive"}
</button>
</div>
<div className="answer {active ? 'active' : ''}">
{quiz.answers[1].text}
<button label="{active ? 'ACTIVE' : 'inactive'}" onClick={toggle}>
{active ? 'ACTIVE' : 'inactive'}
</button>
</div>
This is about as far as I can figure out how to get. I am trying to get it so that when I click one button, the label and text switch to active, while switching the other to inactive, if it is currently active.
I've seen some stuff with react-DOM but I'm wondering if there is a more straight forward way to accomplish this? Thanks in advance.
You can just have the state be the index of the active button, like Nicholas said in the comments:
// the default active button is the first button, button number 0
const [activeButton, setActiveButton] = useState(0);
const toggle = () => {
setSelected(!selected)
}
return(
<div id="quizAnswers">
<div className={`answer ${activeButton === 0 ? 'active' : ''}`}>
{quiz.answers[0].text}
<button label={`${activeButton === 0 ? 'ACTIVE' : 'inactive'}`} onClick={() => setActiveButton(0)}>
{active ? "ACTIVE" : "inactive"}
</button>
</div>
<div className={`answer ${activeButton === 1 ? 'active' : ''}`}>
{quiz.answers[1].text}
<button label={activeButton === 1 ? 'ACTIVE' : 'inactive'} onClick={() => setActiveButton(1)}>
{active ? 'ACTIVE' : 'inactive'}
</button>
</div>
)
And you can reduce duplication and make it generic to more than 2 buttons by using map:
return(
<div id="quizAnswers">
{quiz.answers.map((answer, index) =>
<div className={`answer ${activeButton === index ? 'active' : ''}`}>
{answer.text}
<button label={activeButton === index ? 'ACTIVE' : 'inactive'} onClick={() => setActiveButton(index)}>
{active ? "ACTIVE" : "inactive"}
</button>
</div>
}
</div>
)
Also, note how I changed the syntax in className and label-- you were embedding {} within double quotes (like " foo {bar} baz") which wouldn't work like you were expecting.
Just as an additional example: you can hold a reference to the actual answer object inside of your useState variable. Also, it might be better to create a new component for actual Answer and use it inside the .map function. Or without map function, but why to duplicate code?
const { useState, Fragment } = React;
const DUMMY_QUIZ = {
question: "How to do this?",
answers: [
{ id: 1, text: "Do that" },
{ id: 2, text: "Do this" }
]
};
function QuizAnswers() {
const [selectedAnswer, setSelectedAnswer] = useState();
const quiz = DUMMY_QUIZ;
return (
<div id="quizAnswers">
<p>Using map function</p>
{quiz.answers.map((a) => (
<QuizAnswer
item={a}
key={a.id}
onClick={() => setSelectedAnswer(a)}
isSelected={a === selectedAnswer}
/>
))}
<p>Without map function</p>
<Fragment>
<QuizAnswer
item={quiz.answers[0]}
onClick={() => setSelectedAnswer(quiz.answers[0])}
isSelected={quiz.answers[0] === selectedAnswer}
/>
<QuizAnswer
item={quiz.answers[1]}
onClick={() => setSelectedAnswer(quiz.answers[1])}
isSelected={quiz.answers[1] === selectedAnswer}
/>
</Fragment>
</div>
);
}
function QuizAnswer({ item, onClick, isSelected }) {
return (
<div className={`answer ${isSelected ? "active" : ""}`}>
{item.text}
<button label={`${isSelected ? "ACTIVE" : "inactive"}`} onClick={onClick}>
{isSelected ? "ACTIVE" : "inactive"}
</button>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<QuizAnswers />);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
<div id="root"></div>

How to toggle class on onclick in map function?

Toggling on a single element is a breeze. But I'm having a difficulty toggling with map function. Clicking a child element should toggle "active". But what's happening is that every element gets the class "active". Take a look:
constructor() {
super()
active: false
this.toggleClick = this.toggleClick.bind(this)
}
toggleClick() {
this.setState(state=> ({
active: !state.active
})
)
}
...in my function class...
function ThisClass(props){
return(
<div>
{
items.map((item,i) => {
return(
<span role="button" className={`${props.active ? 'active' : ''}`} key={i} onClick={() => props.toggleClick(i)}>{item.text}</span>
)
})
}
</div>
)
}
This is my desired output:
<div>
<span class="active">A</span>
<span class="">B</span>
<span class="">C</span>
</div>
Instead, this becomes the result
<div>
<span class="active">A</span>
<span class="active">B</span>
<span class="active">C</span>
</div>
And of course, toggling should be working. a single click would make the current active. And clicking it again would remove the active state. Also, By clicking the current state, the previous active element should be stripped off with active.
Here's my own solution(along with #404notBrighton): In my state:
...instead of
this.state = {active:false}
I've changed it to
this.state = {active:null}
in my toggleClick() I've put
this.setState({ active: i });
if (this.state.active === i) {
this.setState({ active: null })
}
then finally in my class...
<span role="button" className={`${props.active === i ? 'active' : ''}`} key={i} onClick={() => props.toggleClick(i)}>
try assigning your "active" state an index instead of a boolean
change your code
from
className={${props.active ? 'active' : ''}}
to
className={${props.active === i ? 'active' : ''}}
Your toggle function must look like this
toggleClick(i) {
this.setState({ active: i })
}
As I understand, you want to have only one active item.
You need to keep two state like selectedItemId and selectedItemState.
And update their values when button is clicked.
So you can try something like this:
import React, { Component } from "react";
class App extends Component {
state = {
items: [{ id: 1, text: "A" }, { id: 2, text: "B" }, { id: 3, text: "C" }],
selectedItemId: null,
selectedItemState: false
};
toggleClick = id => {
if (id === this.state.selectedItemId) {
this.setState({
selectedItemState: !this.state.selectedItemState
});
} else {
this.setState({
selectedItemId: id,
selectedItemState: true
});
}
};
render() {
const { selectedItemId, selectedItemState } = this.state;
return this.state.items.map(el => (
<div key={el.id}>
<span
role="button"
className={
el.id === selectedItemId && selectedItemState ? "active" : ""
}
onClick={() => this.toggleClick(el.id)}
>
{el.text} -{" "}
{el.id === selectedItemId && selectedItemState ? "active" : "passive"}
</span>
<br />
</div>
));
}
}
export default App;
Sample codesandbox:
https://codesandbox.io/s/spring-thunder-w711z

Hide all div and show one div on clicking multiple button

I am trying to fit 3 component in a single page by hiding/showing on a div.But I am not really getting into how to do it.This is the first div.
<div>
<p>What is the type of your property?</p>
<button >Residence</button>
<button>Commercial</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
Only If i click the 'Commercial' or 'Next' button it would go into the second div and first div will hide.
<div>
<p>What is the type of your commercial property?</p>
<button>Office</button>
<button>Restaurant</button>
<button >Outlet</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
and lastly if i click 'restaurant' button from the first div and any button of the second div except the back button it will go into the third div and other div will hide.this is the third div.
<div>
<div className='slider' style={{ marginTop:'165px',marginLeft:'319px',width:'700px',backgroundColor:'EF5350'}} >
<Slider min={850} max={5000} value={value} onChangeStart={this.handleChangeStart}
onChange={this.handleChange}
onChangeComplete={this.handleChangeComplete}
/>
<div className='value'>{value} Squarefeet</div>
<div style={{marginTop:'86px'}}>
<span onChange={this.handleChange} onClick={() => this.saveValue()} >Next</span>
<span onChange={this.handleChange} onClick={() => this.saveValue()} >Next</span>
</div>
</div>
</div>
I tried to do it this way. But it will not work.
import React from 'react';
import Link from "next/link";
class Jh extends React.Component {
constructor() {
super();
this.state = {
shown: true,
hide: false
};
}
toggle() {
this.setState({
shown: !this.state.shown
});
}
toggles() {
this.setState({
shown: !this.state.hide
});
}
render() {
var shown = {
display: this.state.shown ? "block" : "none"
};
var hidden = {
display: this.state.shown ? "none" : "block"
}
return (
<div>
<button onClick={this.toggle.bind(this)} style={ shown }>
<div>
<p>What is the type of your property?</p>
<button >Residence</button>
<button>Commercial</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
</button>
<button onClick={this.toggles.bind(this)} style={ hidden }>
<div>
<p>What is the type of your commercial property?</p>
<button>Office</button>
<button>Restaurant</button>
<button >Outlet</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
</button>
</div>
)
}
}
export default Jh
What should be my approach?
There are many patterns to achieve a "switch case", I'll try to show my favorites:
For sipmlicity, I'll use a generic use case.
Straight Forward
Managing visible state for every component:
return {visible && <CoolComponent id={1} />};
Switch case in disguise
Manage a state of object keys. (currentCounter)
const countersPicker = {
counter1: <Counter id={1} />,
counter2: <Counter id={2} />,
coolComponent: <CoolComponent id={3} />
};
return {countersPicker[currentCounter]};
Here you also can take action on the object, for example, adding a header:
return {Object.entries(countersPicker).map(([key,component]) =>
<div key={key}>
<h1>Component key = {key}</h1>
{component}
</div>
)};
Filter Children
Manage a predicate and use it for filtering/mapping the children.
Check React.Children API.
return (
<FilterComponents predicate={predicate}>
<Counter key={1} id={1} />
<Counter key={2} id={2} />
<CoolComponent key={3} id={3} />
<BestComponent key={4} id={4} />
</FilterComponents>
);
function FilterComponents({ children, predicate }) {
const filteredChildren = React.Children.toArray(children).filter(child =>
// Use the predicate.
// Filter a child by key, key & type or even use ref etc.
);
return <div>{filteredChildren}</div>;
}
I believe you are looking for something like this.
Main things to-do:
Enhance your state-value. Keep track of the different pages in sequence by using an array. Track the current page. Track the start and end of the collection.
Here is the sandbox as well: https://codesandbox.io/s/unruffled-sun-gpzx6
import React from "react";
class Pages extends React.Component {
state = {
currentPage: "property",
pages: ["property", "type", "firstBusiness"],
start: true,
end: false
};
changePage = event => {
const { currentPage, pages } = this.state;
const { name } = event.target;
//check if we are going to end
if (
name == "next" &&
pages[pages.indexOf(currentPage) + 1] === pages[pages.length - 1]
) {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
end: true,
start: false
});
//go to next page
} else if (name == "next") {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
start: false
});
//check if we are going to beginning
} else if (
name == "back" &&
currentPage !== pages[0] &&
pages[pages.indexOf(currentPage) - 1] == pages[0]
) {
this.setState({
currentPage: pages[pages.indexOf(currentPage) - 1],
start: true
});
//go back one page
} else {
this.setState({
currentPage: pages[pages.indexOf(currentPage) - 1],
end: false
});
}
};
goToNextPage = () => {
const { currentPage, pages, end } = this.state;
//check if we are going to end
if (pages[pages.indexOf(currentPage) + 1] === pages[pages.length - 1]) {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
end: true,
start: false
});
//go to next page
} else if (end) {
return;
} else {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
start: false
});
}
};
render() {
const { currentPage, start, end } = this.state;
return (
<div style={{ background: "gray" }}>
{currentPage === "property" ? (
<div>
<p>What is the type of your property?</p>
<button onClick={this.goToNextPage}>Residence</button>
<button onClick={this.goToNextPage}>Commercial</button>
</div>
) : null}
{currentPage === "type" ? (
<div>
<p>What is the type of your commercial property?</p>
<button onClick={this.goToNextPage}>Office</button>
<button onClick={this.goToNextPage}>Restaurant</button>
<button onClick={this.goToNextPage}>Outlet</button>
</div>
) : null}
{currentPage === "firstBusiness" ? (
<div>
<p>Is this your first business?</p>
<button onClick={this.goToNextPage}>Yes</button>
<button onClick={this.goToNextPage}>No</button>
</div>
) : null}
<div>
<button onClick={this.changePage} name="back" disabled={start}>
Back
</button>
<button onClick={this.changePage} name="next" disabled={end}>
Next
</button>
</div>
</div>
);
}
}
export default Pages;
So essentially you want router like functionality. Here is one approach:
class FirstPage extends React.Component {
render() {
//...first page content
}
}
class SecondPage extends React.Component {
render() {
//...second page content
}
}
const pages = {
first: FirstPage,
second: SecondPage
};
class App extends React.Component {
constructor() {
this.state = {
page: 'first'
};
}
render() {
const PageComponent = pages[this.state.page];
return <div>
<button onClick={() => this.setState({page: 'first'})}>First page</button>
<button onClick={() => this.setState({page: 'second'})}>Second page</button>
<PageComponent/>
</div>
}
}
There are many ways to solve this problem. But in my opinion the best solution is the one which solves the problem in a succinct manner.
Please find below the working solution which I have tried and works like a charm:
import React from "react";
class Pages extends React.Component {
state = {
activeTab: 1
};
toggle = tab => {
this.setState({
activeTab: tab
});
};
togglePage = page => {
if (page === "next") {
this.setState({
activeTab: this.state.activeTab + 1
});
} else if (page === "back") {
this.setState({
activeTab: this.state.activeTab - 1
});
}
};
render() {
return (
<div style={{ background: "#dedede" }}>
<div hidden={this.state.activeTab === 1 ? false : true}>
<p>1) What is the type of your property?</p>
<button class="btn btn-primary" onClick={() => this.toggle(2)}>
Residence
</button>
<button onClick={() => this.toggle(2)}>Commercial</button>
</div>
<div hidden={this.state.activeTab === 2 ? false : true}>
<p>2) What is the type of your commercial property?</p>
<button onClick={() => this.toggle(3)}>Office</button>
<button onClick={() => this.toggle(3)}>Restaurant</button>
<button onClick={() => this.toggle(3)}>Outlet</button>
</div>
<div hidden={this.state.activeTab === 3 ? false : true}>
<p>3) Is this your first business?</p>
<button onClick={this.NextAction}>Yes</button>
<button onClick={this.NextAction}>No</button>
</div>
<div>
<button
onClick={() => this.togglePage("back")}
name="back"
disabled={this.state.activeTab === 1 ? true : false}
>
Back
</button>
<button
onClick={() => this.togglePage("next")}
name="next"
disabled={this.state.activeTab === 3 ? true : false}
>
Next
</button>
</div>
</div>
);
}
}
export default Pages;
In react we have a hidden attribute which you can use to show/hide the elements without having to write any css for the same.
And I have tried to solve the problem with the least number of variables.
The sandbox for the same can be found here : https://codesandbox.io/s/mysolution-g8fu6
Hope this helps!

Add a class for the active button ReactJS

When you click on a button, you should change its class. When I click on one of the buttons, the class changes for both. I need the class to be added only to the active button, and if I click on another, then the first button will have the class disappear and the second will appear. Where is the error?
import React, { Component } from 'react';
class trueName extends Component {
constructor(props) {
this.state = {
name: {},
};
}
editName = (names)=>{
this.setState({name:names});
}
someFunct(name) {
this.setState({ active: name })
}
render() {
const {name}=this.state;
return(
<div >
<div className="SelectName">
<span>{this.state.name}</span>
</div>
<button
className={this.state.active === name ? 'active' : ''}
onClick={ () => {this.editName(John);this.someFunct(name)}}
key ='1'>
<span>My name John</span>
</button>
<button
className={this.state.active === name ? 'active' : ''}
onClick={ () => {this.editName(Donald);this.someFunct(name)}}
key ='2'
>
<span>My name Donald</span>
</button>
</div>
)
}
}
export default trueName;
You are setting state.name and then setting state.active to the same value, so this.state.active === this.state.name is always true and the active class gets applied.
This might help:
constructor(props) {
super(props)
this.state = {
name: null
}
}
editName = name => {
this.setState({ name: name })
}
render() {
const { name } = this.state
return (
<div>
<div className="SelectName">
<span>
<pre>{name}</pre>
</span>
</div>
<button
className={name === "John" ? "active" : ""}
onClick={() => {
this.editName("John")
}}
>
<span>My name John</span>
</button>
<button
className={name === "Donald" ? "active" : ""}
onClick={() => {
this.editName("Donald")
}}
>
<span>My name Donald</span>
</button>
</div>
)
}

React Toggle Active Class between multiple Reactstrap Buttons

I am new to React and Reactstrap. I am trying to set the active class or active attribute to a single button onclick. My current setup toggles all the buttons at the same time. What the best way to toggle the active states independently between the buttons states when clicked?
import React, { Component } from 'react'
import { Button } from "reactstrap";
export class Payment extends Component {
constructor(props) {
super(props);
this.state = {
paymentSelection: 'credit',
active: false
}
}
toggleContent = (event) => {
const currentState = this.state.active;
event.preventDefault();
this.setState({
paymentSelection: event.target.value,
active: !currentState
})
}
switchContent = (value) => {
switch (value) {
case 'credit':
return <div>
<p>Credit Content Here</p>
</div>;
case 'paypal':
return <div>
<p>PayPal Content Here</p>
</div>;
case 'amazon':
return <div>
<p>Amazon Content Here</p>
</div>;
case 'more':
return <div>
<p>More Content Here</p>
</div>;
default:
return null;
}
}
render() {
const { paymentSelection } = this.state;
const { active } = this.state;
return (
<div className="container-fluid payment-btn-group">
<Button outline className={active ? 'active': null} color="secondary" value="credit" onClick={this.toggleContent} >Credit Card</Button>
<Button outline className={active ? 'active': null} color="secondary" value="paypal" onClick={this.toggleContent} >PayPal</Button>
<Button outline className={active ? 'active': null} color="secondary" value="amazon" onClick={this.toggleContent} >Amazon</Button>
<Button outline className={active ? 'active': null} color="secondary" value="more" onClick={this.toggleContent} >+ More</Button>
{this.switchContent(paymentSelection)}
</div>
);
}
}
export default Payment
You can set active class like this
className={paymentSelection ==='credit' ? 'active' : null}
You already have payment selection in the state you just need to check that apply it.
Demo

Resources