0

I am trying to create a chatbox component like the facebook-status post. There are buttons on the bottom. When a user clicks them I load various box styles. I need to set the class of current button "active".

My component is not controlled by a parent so I cannot set any prop bases solution. I know how to implement a ternary operator but don't know how can I use it here?

I have tried these solutions but these all are parent based. React Js conditionally applying class attributes react change the class of list item on click

import React from "react"
import StyleButton from "./StyleButton"

class Post extends React.Component {
    constructor() {
        super()
        this.state = {
            selectedClass: 'red',
            displayBtns: true,
            buttons: [1,2,3,4,5,6]
        }
    }

    handleDisplayBtnClick = () => {
        this.setState(prevState => ({
            displayBtns: !prevState.displayBtns 
        }))
    }

    handleChange = e => {
        let btnId = e.currentTarget.dataset.id;
        switch (btnId) {
            case '1':
                this.setState({selectedClass: "purple" })
                break;
            case '2':
                this.setState({selectedClass: "cyan" })
                break;
            case '3':
                this.setState({selectedClass: "ballons" })
                break;
            case '4':
                this.setState({selectedClass: "clouds" })
                break;
            case '5':
                this.setState({selectedClass: "thumbs" })
                break;
            case '6':
                this.setState({selectedClass: "smile" })
                break;
            default: 
                this.setState({selectedClass: "default" })
          }
    }

    render() {
        return(
            <div className={`bg container ${this.state.selectedClass}`} >
                <input className="input" placeholder="What's on your mind?" type="text"/>
                <button className={this.state.displayBtns ? 'closeBtn' : 'openBtn'} onClick={this.handleDisplayBtnClick}>&nbsp;</button>

                { this.state.displayBtns ? 
                    <div className="btns" >
                        {this.state.buttons.map(eachButtonNumber => 
                            <button 
                                key={eachButtonNumber} 
                                data-id={eachButtonNumber} 
                                onClick={this.handleChange}
                            >&nbsp;</button>
                        )}
                    </div> 
                : null }
            </div>
        )
    }
}

export default Post

I want to add an "active" class when I click it on the buttons which are rendered from "buttons.map". Right now my buttons is changing the Div class to change the background.

<button 
key={eachButtonNumber} 
data-id={eachButtonNumber} 
onClick={this.handleChange} >&nbsp;</button>

Also, want to know If this is the right way of doing it?

Posted the whole code and GIF at "https://github.com/ankursehdev/facebook-post-box-reactjs"

My Rendered HTML - I want "active" on the list of buttons.

<div class="parent">
<div class="bg container smile">
    <input class="input" placeholder="What's on your mind?" type="text">
    <button class="closeBtn">&nbsp;</button>
    <div class="btns">
        <button data-id="1">&nbsp;</button>
        <button data-id="2">&nbsp;</button>
        <button data-id="3">&nbsp;</button>
        <button data-id="4">&nbsp;</button>
        <button data-id="5">&nbsp;</button>
        <button data-id="6">&nbsp;</button>
    </div>
</div>
</div>
Ankur Sehdev
  • 106
  • 1
  • 1
  • 8

2 Answers2

1

If your buttons have a little more detail to them this is pretty easy. If instead of [1,2,3,4,5,6] for your buttons, if the array had an object for each button, each button could have properties that can be matched to the state. So maybe like this:

[
  {id: 1, buttonName: 'purple'},
  {id: 2, buttonName: 'cyan'},
  {id: 3, buttonName: 'ballons'},
  {id: 4, buttonName: 'clouds'},
  {id: 5, buttonName: 'thumbs'},
  {id: 6, buttonName: 'smile'},
]

Then in your map loop, each button is checking if the selectedClass state matches its buttonName property and adding an active class in that case. Note you will need to point to id property now for the numeric id of each button.

{this.state.buttons.map(eachButtonNumber => 
  <button
    className={this.state.selectedClass === eachButtonNumber.buttonName && 'active'}
    key={eachButtonNumber.id} 
    data-id={eachButtonNumber.id} 
    onClick={this.handleChange}
  >
    &nbsp;
  </button>
)}
BugsArePeopleToo
  • 2,976
  • 1
  • 15
  • 16
  • Yes, I have full control over that array. And do you think this is the right approach to write React app in general? I mean the full application. and Thanks – Ankur Sehdev Mar 27 '19 at 14:09
  • It's the most React-y way to manage conditional classes in a loop that I know of. Happy to help! – BugsArePeopleToo Mar 27 '19 at 14:13
  • I am getting a warning after using this: So I am using the ternary operator. Following is the warning. > Warning: Received `false` for a non-boolean attribute `className`. If you want to write it to the DOM, pass a string instead: className="false" or className={value.toString()}. If you used to conditionally omit it with className={condition && value}, pass className={condition ? value : undefined} instead. – Ankur Sehdev Mar 27 '19 at 14:21
0

Simplest way to do this is to get the className to be applied inside the render before returning the jsx.

Like in render you can write the condition as below

let classNameStyle = "" 
if(this.state.displayBtns)
   classNameStyle = 'closeBtn '
else
   classNameStyle = 'openBtn '

if(this.state.active)
   classNameStyle = classNameStyle + 'active'

Now apply this classNameStyle value to className property of button. (Note ) See the space in assignment of first className

Raj Saraogi
  • 1,780
  • 1
  • 13
  • 21
  • Hello Raj, I am trying to apply active class to ``` not the openBtn and CloseBtn. There is a list of buttons from the buttons.map. – Ankur Sehdev Mar 27 '19 at 04:26