sWarren
sWarren

Reputation: 473

Conditional CSS Styling Question when class is already present

I have a stateless function that maps and returns multiple list items. They already have a class assigned to them ("list-group-item"), as you can see. I now want to assign a conditional CSS class to them as well, that will strike through the text of these list items (CSS class is named "strike-through"), based on when the input element is checked/unchecked.

This 'event' would be passed up through the prop onChange= {() => props.onDone(todo)} so that that the stateful component is 'aware' of the change in there being a list item that is checked/unchecked.

How can I finish this logic so that a handler in my stateful component receiving the event, can toggle the condition (in the form of a boolean) based on the checked/unchecked box, then pass this condition back to my stateless component to change the class based on the condition (checked/unchecked)? (Checked boxes should have the CSS class, unchecked should not, based on the condition). For context please see below.

Stateless Function where I want a conditional class applied to the <li> where there is a class already called "list-group-item" and a prop onDone in the <input> that passes up change if a checkbox is checked/unchecked:

import React from 'react';

const Todo = props => (
  <div className="container">
  <div className="col-md-8">
  <div className="panel panel-default">
  <div className="panel-heading">Your Current Todos</div>
    <ul className = "list-group">
      {props.todo.map(todo => {
          return <li className = "list-group-item" key ={todo.id}><input type="checkbox" onChange= {() => props.onDone(todo)}/>{todo.text}<a onClick={() => props.onEdit(todo)}
          className="edit-todo glyphicon glyphicon-edit d-flex justify-content-between align-items-center" href="#"></a><a onClick={() => props.onDelete(todo)}
          className="delete-todo glyphicon glyphicon-trash" href="#"></a></li>
        })
      }
    </ul>
  </div>
  </div>
  </div> 
    );

export default Todo;

State object:

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      id: 0,
      text: '',
      editText: '',
      editId: '',
      priority: 1,
      isEdit: false,
      completed: false,
      todos:[]
    };

Handler that would receive event and toggle state (this.state.completed is reserved for this):

    handleComplete(todo){
 //todo's properties can be accessed with todo.text for example if need to modify.
 //Receives the event from my prop `onChange= {() => props.onDone(todo)}`
//Toggle this.state.completed so that based on this my stateless component can receive conditional styling

    }

Upvotes: 1

Views: 151

Answers (2)

Keith Brewster
Keith Brewster

Reputation: 3662

I'm not sure the shape of your todo data, I'm just going to assume your todos state is an array of todo objects. You can add a key like:

todo = {
    id: 1,
    text: "example",
    completed: false
};

Your event handler would just need to toggle the completed state. Something like:

  handleComplete = todo => {
    this.setState({
        todos: this.state.todos.map(el => {
          if (el.id === todo.id) {
            const newObj = Object.assign({}, el);
            newObj.completed = !el.completed;
            return newObj;
          }
          return el;
        })
      });
  };

Then when mapping over your todo objects, you can change the className to a template string and apply a class conditionally like:

<li className=`{list-group ${completed && "strike-through"}}`>

Upvotes: 2

sme
sme

Reputation: 4163

If I understand your code correctly, you should just be able to conditionally determine the class name, based on the completed property of your todo variable. For example,

<li className={'list-group-item' + todo.completed ? ' strike-through' : ''} ... />

Upvotes: 1

Related Questions