How to toggle the css of a mapped button? - javascript

I'm just trying to figure out how to toggle a css class for an individual button that is generated from a mapped array.
My code works, but it toggles every mapped button, not just the button selected.
<div className='synonym-keeper'>
{synArr.map((syn) => (
<button
className={`synonym ${isPressed && 'active'}`}
onClick={() => toggleIsPressed(!isPressed)}
>
{syn}
</button>
))}
</div>
How do I make just the selected button's css toggle?

Create another component called Togglebutton and keep the toggle logic in it. That way you can toggle the individual button.
This would also work:
const synArr = ["button 1", "button 2", "button 3"];
const ToggleButton = ({ text }) => {
const [isPressed, toggleIsPressed] = React.useState(false);
return (
<button
className={`synonym ${isPressed && "active"}`}
onClick={() => toggleIsPressed(!isPressed)}
>
{text}
</button>
);
};
function App() {
return (
<div className="synonym-keeper">
{synArr.map((syn) => (
<ToggleButton text={syn} key={syn}/>
))}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
.synonym.active {
background-color: green;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>

I resolved it by making an array for the className and changing its contents onClick, as below:
<div className='synonym-keeper'>
{synArr.map((syn, idx) => (
<button
className={`synonym ${isPressed[idx]}`}
onClick={() => {
const newIsPressed = [...isPressed];
newIsPressed[idx] === ''
? (newIsPressed[idx] = 'active')
: (newIsPressed[idx] = '');
setIsPressed(newIsPressed);
}}
>
{syn}
</button>
))}
</div>
This resolves the issue and allows me to select one or more buttons sequentially. I really like the cleanliness of Amila's answer though so I will mark theirs as accepted.

Related

onClick function is not called after I have enabled the button in Reactjs

I have a textarea and a button. The button is disabled by default and when the user starts typing, I enable the button to be clicked. But the problem is that, the onClick function is not called while already disabled = false was set.
I've seen this: button onClick doesn't work when disabled=True is initialized (Reactjs)
Seems to be a good idea, but after I setState with the new value, my component is re-rendering, and I don't really want that.
const refText = useRef(null);
const refBtn = useRef(null);
function handleBtnStatus(e) {
let text = e.target.value;
if(text.replace(/\s/g, "").length > 0) {
refBtn.current.disabled = false;
}
else {
refBtn.current.disabled = true;
}
}
function postThis() {
console.log("You posted! Text:", refText.current.value);
// disable again
refBtn.current.disabled = true;
// delete previous text wrote
refText.current.value = "";
}
return (
<>
{isLogged && (
<div className="container">
<div className="content">
<div className="utool-item-text">
<textarea name="textArea" placeholder="Write something.." ref={refText} onChange={(e) => handleBtnStatus(e)}></textarea>
</div>
<div className="utool-item-post">
<button className="ust-btn-post" ref={refBtn} disabled={true} onClick={postThis}>Da Tweet</button>
</div>
</div>
<div className="posts-section">
<div className="list-posts">
{posts.map((p) => {
return (p.hidden === false ? (
<div className="post" key={p.id}>
<div className="post-text">
<span>{p.text}</span>
</div>
</div>
) : (''))
})}
</div>
</div>
</div>
)}
</>
)
Any help?
Use state instead of refs, re-rendering is ok for your case
Simplified example:
import React, { useState } from 'react';
const SimpleExample = () => {
const [textAreaValue, setTextAreaValue] = useState('');
return (
<>
<button disabled={!textAreaValue} onClick={() => console.log('onClick handler')}>
click me
</button>
<textarea value={textAreaValue} onChange={(e) => setTextAreaValue(e.target.value)} />
</>
);
};
And I would recommend checking this Use state or refs in React.js form components?

How to Handle multiple radio button inputs with one onChange function handler

i have a scenario where based on a number(say numberOfFlags) i want to render numberOfFlags times an radio button group.Each group has two radio buttons approve and reject as per screenshot attached how to get values of all inputs when they change?
An lastly i have to store result of all radio buttons (approve/reject) in an array and send to API
You need to use two parameters on onChange function. One is for current index and another is for Approve/Reject.
Like below code snippet
onchange = handleOnChage(index, isApproveClicked)
You can achive this in many different ways, but I would probably simple create a state with an array of values in the parent component and pass it to each and every item to toggle its own state depending action.
App.js
export function App() {
const [list, setList] = useState([false, false, false]);
const updateItem = (value, index) => {
let copyList = [...list];
copyList[index] = !value;
setList(copyList);
};
console.log(list)
return (
<div className="App">
{list && (
<>
{list.map((value, index) => (
<Item values={[value, index]} updateItem={updateItem} key={index+"_check"} />
))}
</>
)}
</div>
);
}
Item.js
export default function Item({ values, updateItem }) {
return (
<>
<input
onChange={() => updateItem(values[0], values[1])}
type="checkbox"
checked={values[0] ? "checked" : ""}
/>
</>
);
}
Presented below is one possible way to achieve the desired objective.
Code Snippet
const {useState} = React;
const Thingy = ({...props}) => {
// num-of-flags is obtained from props
const { numOfFlags: nf} = props || {};
// if it is null or not above 0, return "invalid" message to parent
if (!(nf && nf > 0)) return "invalid num-of-flags";
// state variable to store approve/reject status
const [statusObj, setStatusObj] = useState({});
// JSX to render the UI & handle events
return (
<div>
{([...Array(nf).keys()].map(grpIdx => (
<div className="grpBox">
Group num {grpIdx+1} <br/>
<input type='radio' name={grpIdx} id={grpIdx} value={'approve'}
onChange={() => setStatusObj({
...statusObj, [grpIdx]: 'approve',
})}
/>
<label for={grpIdx}>Approve</label>{" "}
<input type='radio' name={grpIdx} id={grpIdx} value={'reject'}
onChange={() => setStatusObj({
...statusObj, [grpIdx]: 'reject',
})}
/>
<label for={grpIdx}>Reject</label>
</div>
)))}<br/>
<button
onClick={() => {
// make API call here
// for verification, displaying an alert-message showing the status
const displayMsg = [...Array(nf).keys()].map(
gi => "Group num " + (+gi+1) + " : " + (gi in statusObj ? statusObj[gi] : '__')
).join(', ');
alert(`Approve-Reject status is: ${JSON.stringify(displayMsg)}`);
}}
>
Submit
</button>
</div>
);
};
ReactDOM.render(
<div>
<div className="demoTitle">DEMO</div>
<Thingy numOfFlags={5} />
</div>,
document.getElementById("rd")
);
.demoTitle {
margin-bottom: 5px;
font-size: 20px;
text-decoration: underline;
}
.grpBox {
margin: 5px; padding: 10px;
border: 2px solid purple;
width: max-content;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="rd" />
Explanation
Inline comments added to the snippet above.
PS: If you'd like to add value to stackoverflow community,

How to Create 2D Grid by Repeating a Component certain times in a Loop in reactJS?

I am Working on Movie Ticket Booking Website. I Want to make a Grid Layout of 4x7. So What i Thought is i would Create a button Component and repeat it in Loop Several Times.
Pseudo Code:
for(var i=0;i<4;i++){
for(var j=0;j<7;j++){
button Component();
}
newline Component();
}
But this type of thing is not supported in reactjs. So What Can i Do for Implementation of above thing? Also When a button is clicked i want to change its color for that i have given ID to button Component so i can do it by DOM Manipulation but how to do that using UseState?
EDIT: I am done with array part but what about Color Change now? I Tried DOM but it returns NULL
CODE:
const items=[];
for(let i=1;i<=20;i++){
let style={
backgroundColor:"White"
};
items.push(<button className="btn btn-danger" onClick={()=>changeColor(i)} style={style} id={"button"+i}/>);
}
function changeColor(index) {
document.getElementById("index").style.backgroundColor="Green";
}
This Thing returns NULL i Do not know why
Using direct DOM manipulation is not recommended, you should instead leverage the reactive render cycle that React provides.
Here is a snippet which declares a Button component that handles its own internal state as an example. Mutiple Buttons are rendered inside a map() in the parent, and each button then controls its own active state.
const { useState } = React;
function App() {
return (
<div>
{[1,2,3].map(n =>(
<Button key={n} label={'Button' + n} />
))}
</div>
)
}
function Button({label}) {
const [active, setActive] = useState(false);
const handleClick = (e) => {
setActive(a => !a);
};
return (
<button
type='button'
className={active ? 'active' : ''}
onClick={handleClick}
>
{label}
</button>
)
}
ReactDOM.render(<App />, document.getElementById('root'));
.active {
background-color: tomato;
}
<script src="https://unpkg.com/react#17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.production.min.js"></script>
<div id='root'></div>
But generally buttons will be used to interact directly with the parent's state, in which case the click handler and state logic will be declared in the parent, with relevant properties being passed down to the children.
const { useState } = React;
function App() {
const [buttons, setButtons] = useState([
{id: 1, label: 'Button 1', active: false},
{id: 2, label: 'Button 2', active: false},
{id: 3, label: 'Button 3', active: false}]);
const handleClick = (buttonId) => {
setButtons(buttons => buttons.map(b =>
b.id === buttonId
? {...b, active: !b.active}
: b));
};
return (
<div>
{buttons.map(b =>(
<Button key={b.id} id={b.id} label={b.label} onClick={handleClick} active={b.active} />
))}
</div>
)
}
function Button({label, id, onClick, active}) {
return (
<button
type='button'
onClick={() => onClick(id)}
className={active ? 'active' : ''}
>
{label}
</button>
)
}
ReactDOM.render(<App />, document.getElementById('root'));
.active {
background-color: tomato;
}
<script src="https://unpkg.com/react#17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.production.min.js"></script>
<div id='root'></div>

How to emulate this jQuery behaviour with reactJS: add/ remove className from different divs

I wanted to learn reactJS, I know jQuery, I want to know how to achieve the below jQuery add class remove class function in reactJS.
There is no proper tutorial for this anywhere for the beginner like me, I here and there saw someone achieved this using an npm package "classNames" but cant understand how to use that. So please someone post a simple and effective code to achieve this so I can learn.
$(document).ready(function(){
$('.sexSelect').click(function(event){
$('.sexSelect').removeClass('active');
$(this).addClass('active');
event.preventDefault();
});
});
.sexSelect.active { color: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>Sex - Click Anyone</h1>
<span class="sexSelect active">MALE </span>
<span class="sexSelect">FEMALE</span>
Create a boolean that represents if the class is active or inactive.
Write the className of your node like this:
className={isMyClass ? 'activeName' : 'inactiveName' }
In the onClick prop of your button attach the function that updates the boolean.
For example, you can achieve something like this with react hooks:
const ToggleClassExample = () => {
const [isMyClass, setIsMyClass] = useState(true);
return (
<div>
<div className={isMyClass ? 'activeName' : 'inactiveName' }>Hello world</div>
<button onClick={() => setIsMyClass(!isMyClass)}>Toogle class</button>
</div>;
);
};
You can use react hooks' useState to store which item was last clicked, and render an active class using a conditional ternary:
const { useState } = React;
const App = () => {
const [selected, setSelected] = useState('male')
return (
<div className='us-none'>
<h1>Sex - Click Anyone</h1>
<span
onClick={() => setSelected('male')}
className={'sexSelect' + (selected === 'male' ? " active" : '')}
>MALE</span>
|
<span
onClick={() => setSelected('female')}
className={'sexSelect' + (selected === 'female' ? " active" : '')}
>FEMALE</span>
</div>
)
}
ReactDOM.render(
<App />,
document.getElementById("react")
);
.sexSelect.active {
color: red;
}
.sexSelect {
cursor: pointer;
}
.us-none {
user-select: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>

ReactJs adding active class to button

I have five buttons, dynamically created. My target is: when any button is clicked to add active class to it, and of course if any other has that active class to remove it. How can I achieve that?
<div>
{buttons.map(function (name, index) {
return <input type="button" value={name} onClick={someFunct} key={ name }/>;
})}
</div>
You need to introduce state to your component and set it in onClick event handler. For example output of render method:
<div>
{buttons.map(function (name, index) {
return <input
type="button"
className={this.state.active === name ? 'active' : ''}
value={name}
onClick={() => this.someFunct(name)}
key={ name } />;
})}
</div>
event handler (element method):
someFunct(name) {
this.setState({ active: name })
}
One of the easiest way to add active class is setting state and changing that state on each switch, by the state value you can change the active class of the item.
I also had an same issue with switching the active class in list.
Example:
var Tags = React.createClass({
getInitialState: function(){
return {
selected:''
}
},
setFilter: function(filter) {
this.setState({selected : filter})
this.props.onChangeFilter(filter);
},
isActive:function(value){
return 'btn '+((value===this.state.selected) ?'active':'default');
},
render: function() {
return <div className="tags">
<button className={this.isActive('')} onClick={this.setFilter.bind(this, '')}>All</button>
<button className={this.isActive('male')} onClick={this.setFilter.bind(this, 'male')}>male</button>
<button className={this.isActive('female')} onClick={this.setFilter.bind(this, 'female')}>female</button>
<button className={this.isActive('child')} onClick={this.setFilter.bind(this, 'child')}>child</button>
<button className={this.isActive('blonde')} onClick={this.setFilter.bind(this, 'blonde')}>blonde</button>
</div>
}
});
hope this will help you!
One of the easiest solution for adding active class to the current button (highlight it) for react developers.
const {useState,Fragment} = React;
const App = () => {
const [active, setActive] = useState("");
const handleClick = (event) => {
setActive(event.target.id);
}
return (
<Fragment>
<button
key={1}
className={active === "1" ? "active" : undefined}
id={"1"}
onClick={handleClick}
>
Solution
</button>
<button
key={2}
className={active === "2" ? "active" : undefined}
id={"2"}
onClick={handleClick}
>
By
</button>
<button
key={3}
className={active === "3" ? "active" : undefined}
id={"3"}
onClick={handleClick}
>
Jamal
</button>
</Fragment>
);
}
ReactDOM.render(
<App/>,
document.getElementById("react")
);
.active{
background-color:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Categories

Resources