How to enable/disable elements from an array in React JS? - javascript

I am trying to create a component where I have a bunch of boxes from an array, that can be turned 'on' and 'off' when each one is individually clicked.
Currently, only a single item from the array can be switched 'on' (shown by the item turning green), however, I would like to be able to turn each item on/off individually.
Interacting with one element should not affect any of the others.
How do I achieve this?
My click event:
handleOnClick = (val, i) => {
this.setState({active: i}, () => console.log(this.state.active, 'active'))
}
Rendering the boxes:
renderBoxes = () => {
const options = this.state.needsOptions.map((val, i) => {
return (
<button
key={i}
style={{...style.box, background: i === this.state.active ? 'green' : ''}}
onClick={() => this.handleOnClick(val, i)}
>
{val}
</button>
)
})
return options
}
Here's a Codepen

What I would do is to create a Box component with its own active state, and pass this to the map in renderBoxes. The benefit of doing it this way is that each Box component will have its own state independent of the parent. That way you can have more than one component as active.
so...
class Box extends React.Component {
constructor(props){
super(props)
this.state={
active: false
}
}
clickHandler = () => {
this.setState({active: !this.state.active})
}
render(){
const { key, children }= this.props
return (
<button
key={key}
style={{...style.box, background: this.state.active ? 'green' : ''}}
onClick={() => this.clickHandler()}
>
{children}
</button>
)
}
}
then have renderBoxes be...
renderBoxes = () => {
const options = this.state.needsOptions.map((val, i) => {
return (
<Box
key={i}
>
{val}
</Box>
)
})
return options
}
here is the codepen I forked off yours.

Related

How to invoke button click in List in Reactjs

I want to have 3 buttons and 3 related components . So that when button click show its related component . Here is my code :
Main Component :
class Main extends Component { constructor(props) {
super(props);
this.state = {
show: false,
}}
onClick(e) {
e.preventDefault()
console.log(e.target.id)
this.setState({ show: !this.state.show }); }
renderTabs() {
var child = this.props.child;
var items = [];
__.forEach(child, (item, index) => {
items.push(
<div>
<Button id={index} onClick={(e) => this.onClick(e)}>{item.data}</Button>
{this.state.show ? (
<CropComponent title={item.data} opts={item.opts} data={item.child} />
) : null}
</div>
);
});
return items;
}
render() {
var opts = this.props.opts;
return (
<div>
{this.renderTabs()}
</div>
)}
}
export default Main;
And here is my CropComponent :
class CropComponent extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<div>hello {this.props.data}</div>
);
}
}
export default CropComponent;
Here are my buttons how can i show its related component when click on a button and hide it on re-click the same button ?
Maintain a show state with initial value as -1. Supply event and index to onClick. In onClick do setState of show as index.
Check if show === index and render the corresponding component.
Like this
this.state = {
show: -1
}
onClick(e,index) {
e.preventDefault()
this.setState({ show: show===index? -1 : index});
}
__.forEach(child, (item, index) => {
items.push(
<div>
<Button id={index} onClick={(e) => this.onClick(e,index)}>{item.data}</Button>
{this.state.show === index ? (
<CropComponent title={item.data} opts={item.opts} data={item.child} />
) : null}
</div>
);
});
Edit:
updated the answer based on helpful comment by #Tony Nguyen

Handling selection of buttons + adding selected items to new array

I am working with a set of arrays which are printed to the screen as buttons via an API call.
I am looking to add my bases/frostings buttons (select one) and then add the key of each one selected to a new OrdersArray. I also need to be able to select multiple toppings (multi-select) and add those to a nested array within the OrdersArray.
I would like to also change the colors of each selected button when they are selected.
My Buttons function generates the buttons.
function Buttons({ list }) {
const style = {
display: 'inline-block',
textAlign: 'center',
border: '1px solid black',
padding: '10px',
margin: '10px',
width: '35%'
}
return (
<div>
{list && list.map(item =>
<button key={item.key}
style={style}
>
{/* <p>{item.key}</p> */}
<p>{item.name}</p>
<p>${item.price}.00</p>
{/* <p>{item.ingredients}</p> */}
</button>
)}
</div>
);
};
My app component renders the buttons.
Class App extends Component {
constructor() {
super();
this.state = {
'basesObject': {},
'frostingsObject': {},
'toppingsObject': {},
selectedButton: null
}
}
componentDidMount() {
this.getBases();
this.getFrostings();
this.getToppings();
}
/* GET DATA FROM SERVER */
getBases() {
fetch('http://localhost:4000/cupcakes/bases')
.then(results => results.json())
.then(results => this.setState({'basesObject': results}))
}
getFrostings() {
fetch('http://localhost:4000/cupcakes/frostings')
.then(results => results.json())
.then(results => this.setState({'frostingsObject': results}))
}
getToppings() {
fetch('http://localhost:4000/cupcakes/toppings')
.then(results => results.json())
.then(results => this.setState({'toppingsObject': results}))
}
render() {
let {basesObject, frostingsObject, toppingsObject} = this.state;
let {bases} = basesObject;
let {frostings} = frostingsObject;
let {toppings} = toppingsObject;
return (
<div>
<h1>Choose a base</h1>
<Buttons on
list={bases}
/>
<h1>Choose a frosting</h1>
<Buttons
list={frostings}
/>
<h1>Choose toppings</h1>
<Buttons
list={toppings}
/>
</div>
);
}
}
I'm new to React, any help would be appreciated! :)
You'll need to pass a function to the buttons that will modify a state value in the parent component when the button is clicked.
In parent:
const addToOrder = item => {
orderArray.push(item);
const newOrder = orderArray.reduce((acc, order) => {
return acc + " " + order.name;
}, "");
setOrder(newOrder);
};
...
<Button addToOrder={addToOrder} />
In Button.js
<button onClick={() => addToOrder(item)} >
Check out the whole thing in this Sandbox
For keeping track of which ones have been clicked you'll need to keep track of button state either in the button component itself or in the parent container if you want to keep the buttons stateless. Then set the button attribute disabled to true or false based on that state.
<button disabled={isButtonDisabled} />
Sorry I didn't have time to flesh the full thing out, but this should get you in the right direction.

conditional passing functions as props to a component

i have this breadcrump component that map over props and renders a list of chip components like this:
class BreadCrumb extends React.Component {
render () {
const {
steps,
activeIndex
} = this.props;
const chips = steps
.map((step,index) => {
return <Chip
key={index}
title={step.category}
onClick = {()=> this.props.selectChip(index)} // this should be passed only if
// active == true
active={activeIndex >= index} />
})
return (
<div className="chip-container">
{chips}
</div>
)
}
}
i need to click on chips only if his active prop is true,
this is the chip component
class Chip extends React.Component {
render(){
const {
active,
title
} = this.props;
const activeClassName = active ? 'chip active' : 'chip';
return (
<div
className = {activeClassName}
onClick = {() => this.props.onClick()} >
<span>{title}</span>
</div>
)
}
}
how can i make chip clickable only if the active prop is true?
For further information selectChip() function sets the state of a component App, parent of Breadcrump component, so it is binded to App component.
You could e.g. make that onClick function as a class method and use a simple condition inside:
class Chip extends React.Component {
handleClick = () => {
if (this.props.active) {
this.props.onClick(); // call only if active props is true
}
}
render() {
const { active, title } = this.props;
const activeClassName = active ? 'chip active' : 'chip';
return (
<div
className = {activeClassName}
onClick = {this.handleClick}
>
<span>{title}</span>
</div>
)
}
}
Either execute the handler or an empty function
onClick = {isActive ? this.props.onClick : () =>{} } >
You can do it like this:-
// If chip component expects a function all the time
<Chip
key={index}
title={step.category}
onClick = {step.active ? ()=> this.props.selectChip(index) : () => {}}
active={activeIndex >= index} />
// If onClick is an optional prop to chip component
<Chip
key={index}
title={step.category}
onClick = {step.active ? ()=> this.props.selectChip(index) : undefined}
active={activeIndex >= index} />
// of onClick handler is optional, possibly an alternative solution
type ChipProps = {
title: string;
active: boolean;
onClick?: ()=>void;
}
<Chip
key={index}
title={step.category}
active={activeIndex >= index}
{...(step.active ? {onClick:()=> this.props.selectChip(index)} : {})}
/>

how to change style of a part of string when click :Reactjs

I will change style a part of string when click. example "TEXT" then click at "T" after that it will change style from black color to red color just T only
In my code, I split text and keep at "split" array when I click at text, it will call handleClick function and send index of character that I click is parameter. For example ("EXAMPLE") when I click E it will send 0 is parameter of handleClick function.
import React,{Component} from 'react'
export default class Test extends Component {
handleClick = (index) => {
console.log(index)
}
render() {
return(
<div>
{this.state.table.map((text) => {{this.state.split
&& this.state.split.map((item, index) => {
return(
<span key={index} onClick={() =>
this.handleClick(index)}>{item}
</span>
);
})}
</div>
)
}
}
You need a state which will maintain the clicked index. Then use that index while rendering your split spans to set different colored className.
You could then apply your style to that class.
export default class Test extends Component {
handleClick = (index) => {
this.setState({ clickedIndex: index });
}
render() {
return (
<div>
{this.state.table.map((text) => {
this.state.split && this.state.split.map((item, index) => {
return (
<span key={index} style={clickedIndex === index ? {color: 'red'} : {}} onClick={() =>
this.handleClick(index)}>{item}
</span>
);
})
})}
</div>
)
}
}

Pass index as state to component using React

I have 4 different divs each containing their own button. When clicking on a button the div calls a function and currently sets the state to show a modal. Problem I am running into is passing in the index of the button clicked.
In the code below I need to be able to say "image0" or "image1" depending on the index of the button I am clicking
JS:
handleSort(value) {
console.log(value);
this.setState(prevState => ({ childVisible: !prevState.childVisible }));
}
const Features = Array(4).fill("").map((a, p) => {
return (
<button key={ p } onClick={ () => this.handleSort(p) }></button>
)
});
{ posts.map(({ node: post }) => (
this.state.childVisible ? <Modal key={ post.id } data={ post.frontmatter.main.image1.image } /> : null
))
}
I would suggest:
saving the button index into state and then
using a dynamic key (e.g. object['dynamic' + 'key']) to pick the correct key out of post.frontmatter.main.image1.image
-
class TheButtons extends React.Component {
handleSort(value) {
this.setState({selectedIndex: value, /* add your other state here too! */});
}
render() {
return (
<div className="root">
<div className="buttons">
Array(4).fill("").map((_, i) => <button key={i} onClick={() => handleSort(i)} />)
</div>
<div>
posts.map(({ node: post }) => (this.state.childVisible
? <Modal
key={ post.id }
data={ post.frontmatter.main.[`image${this.state.selectedIndex}`].image }
/>
: null
))
</div>
</div>
);
}
}
This is a good answer which explains "Dynamically access object property using variable": https://stackoverflow.com/a/4244912/5776910

Categories