Marking An Item As Complete

Goals

  • Allow a user to mark an item as complete or incomplete.

  • Understand how to listen for user events with React.

Overview

In this lesson, we'll allow our users to mark items as complete and incomplete. As they do, we will ask the server to update the item's status in its database. This process will look a lot like the process for adding an item, with some additional complexity.

First off, We'll have to write the event listener ourselves in the Item component. Don't worry, we'll walk you through every step!

Secondly, we need to pass the appropriate information to ListStore, so it can make the correct AJAX request. To do so, we'll have to use props to fetch the item's id value.

Let's get started!

Steps

Step 1

Let's add a click listener to our Item component's complete button. Find the line of code that is creating the completion button, and add an onClick attribute to make React listen for your users' clicks. Your code should look like this:

<span className='complete-button' onClick={this.handleComplete}>{'\u2714'}</span>

Now, let's write the handleComplete function.

handleComplete: function() {
  alert('trying to complete item with an id of ' + this.props.id)
}

Refresh the page, and try completing an item. What happens? How does the page know the item's id?

Your Item component should now look like this:

var Item = React.createClass({
  render: function() {
    var itemClass = this.props.completed ? 'item completed' : 'item'
    return (
      <li className={itemClass}>
        <span className='complete-button' onClick={this.handleComplete}>{'\u2714'}</span>
        <div className='description'>{this.props.description}</div>
        <span className='delete-button'>{'\u2718'}</span>
      </li>
    )
  },

  handleComplete: function() {
    alert('trying to update item with an id of ' + this.props.id)
  }
})

Step 2

Now, we're going to tell ListStore to mark this item as complete/incomplete. Remove the alert from last step, and add the following code.

handleComplete: function() {
  ListStore.toggleCompleteness(this.props.id)
}

Step 3

Now, let's write the logic for updating an item! Open up store.js, and add the following code to the toggleCompleteness function. replace 'YOUR-LIST-NAME-HERE' with your list's name.

var item = findItemById(itemId)
var currentCompletedValue = item.completed

var updateRequest = $.ajax({
  type: 'PUT',
  url: "https://listalous.herokuapp.com/lists/YOUR-LIST-NAME-HERE/items/" + itemId,
  data: { completed: !currentCompletedValue }
})

We're using the pre-written findItemById method to fetch the correct item, and then checking its current completed value. We then tell the server to toggle its completeness from true to false, or false to true. Refresh the page and try marking an item as complete. Check the network tab to see if a new request was made!

Step 4

Finally, we'll update the specified item's completeness value in the items array, and tell the components to re-render themselves. Add this code to the bottom of the toggleCompleteness function:

updateRequest.done(function(itemData) {
  item.completed = itemData.completed
  notifyComponents()
})

Mark an item as complete, and see it turn gray! If you mark a completed item as incomplete, it should change colors, too.

Explanation

Here's what store.js should now look like:

ListStore = {

  getItems: function() {
    return items
  },

  loadItems: function() {
    var loadRequest = $.ajax({
      type: 'GET',
      url: "https://listalous.herokuapp.com/lists/YOUR-LIST-NAME-HERE/"
    })

    loadRequest.done(function(dataFromServer) {
      items = dataFromServer.items
      notifyComponents()
    })
  },

  addItem: function(itemDescription) {
    var creationRequest = $.ajax({
      type: 'POST',
      url: "http://listalous.herokuapp.com/lists/YOUR-LIST-NAME-HERE/items",
      data: { description: itemDescription, completed: false }
    })

    creationRequest.done(function(itemDataFromServer) {
      items.push(itemDataFromServer)
      notifyComponents()
    })
  },

  toggleCompleteness: function(itemId) {
    var item = findItemById(itemId)
    var currentCompletedValue = item.completed

    var updateRequest = $.ajax({
      type: 'PUT',
      url: "https://listalous.herokuapp.com/lists/YOUR-LIST-NAME-HERE/items/" + itemId,
      data: { completed: !currentCompletedValue }
    })

    updateRequest.done(function(itemData) {
      item.completed = itemData.completed
      notifyComponents()
    })
  }
}

You've now written three ajax requests, making a modern, dynamic web page. Don't worry if you didn't understand every line of code – JavaScript is complex stuff!

There are many more features you could add (deleting items, sorting items, etc.) but in our next lesson, we'll add the most important feature: the ability of users to actually use your site!

Next Step: