Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strike through any item in a list created using material ui and Reactjs

I am trying to strike through a list item once a user has clicked on that particular item.

I have created a function to conduct the style change

const completed = () =>{
     return document.getElementById("demo").style.textDecoration='line-through'
};

The list is generated as below, i have used material ui library

 <List dense={dense} >
      {items.slice(0).reverse().map(x=> (
           <ListItem key={x.id} button id="demo" onClick={completed} divider>
                 <ListItemText primary={listItems(x)}/>
                 <ListItemSecondaryAction />
           </ListItem>

       ))}                              
</List>

From the code i have written i am able to strike only through the first item of the list. Whenever i add new items , always the only item i am able to strike through is the first item.

I am trying to find a way to apply this to all the elements on the list

like image 942
George Silva Avatar asked Mar 02 '23 16:03

George Silva


2 Answers

It is not a good practice to use document.getElementById() in React because then you are accessing the DOM directly. Instead, you have to use ref.

From official React documentation

When to Use Refs There are a few good use cases for refs:

  • Managing focus, text selection, or media playback.
  • Triggering imperative animations.
  • Integrating with third-party DOM libraries.

But in your case we can easily do this by using React state. I assume that your items is stored in your component state and in a todo item, you need to store whether it is completed or not ( a boolean value ). You can update the code like the following.

const completed = (id) => {
   /* update the state by changing the completed value of the
      clicked todo item */
   this.setState({
      items : this.state.items.map(item => {
         if(item.id === id){
            item.completed = true;
         }
         return item;
      })
   })

}

<List dense={dense}>
  {this.state.items
    .reverse()
    .map(x => (
      <ListItem
        key={x.id}
        button
        // add a unique id
        id={x.id}
        
        // add a strike style depending on the completed property of the todo item
        style={{ textDecoration : x.completed ? 'line-through' : 'none' }} 
        
        // call completed with the id
        onClick={() => completed(x.id)} 

        divider
      >
        <ListItemText primary={listItems(x)} />
        <ListItemSecondaryAction></ListItemSecondaryAction>
      </ListItem>
    ))}
</List>
like image 162
Nuwan Karunarathna Avatar answered Mar 05 '23 07:03

Nuwan Karunarathna


Id's should be all unique in HTML. You should add dynamic id-values to each element and send the id in function-call like following.

const completed = (id) => {
 document.getElementById(id).style.textDecoration='line-through'
}

<List dense={dense}>
  {items
    .slice(0)
    .reverse()
    .map(x => (
      <ListItem
        key={x.id}
        button
        id={x.id} // Add dynamic ID
        onClick={() => completed(x.id)} // Send ID to function
        divider
      >
        <ListItemText primary={listItems(x)} />
        <ListItemSecondaryAction></ListItemSecondaryAction>
      </ListItem>
    ))}
</List>

like image 36
Jimi Pajala Avatar answered Mar 05 '23 07:03

Jimi Pajala