Sign up for a Parse account to implement this tutorial and more!

Sign Up

Icon_todo_ios
Todo App with JavaScript

Learn how to create the canonical Backbone todo application using Parse as the backend to persist user accounts and data.

JavaScript

Download code for this tutorial:

.zip File GitHub

Using the JavaScript SDK, we can extend the canonical Backbone todo application with user authentication and data persistence across devices. Because our SDK is based on Backbone, extending this application to use Parse is a breeze.

This tutorial will guide you through the code for the todo application. You can play around with the live application here. You'll note that the entire application is composed of simple static files. This is the beauty of letting Parse handle the backend for your JavaScript app.

Dependencies

The app requires:

Note that it does not require Backbone since the Parse JavaScript SDK is a fork of Backbone and does not require any other JavaScript library. Here, we're using jQuery and Underscore for elements that are specific to this app, but you can choose to use any library you want.

Templates

We use Underscore templates for all the views. They are directly placed in index.html as script blocks. For example, this is the template for a single todo item:

<script type="text/template"  id="item-template">
  <li class="<%= done ? 'completed' : '' %>">
    <div class="view">
      <input class="toggle" type="checkbox" <%= done ? 'checked="checked"' : '' %>>
      <label class="todo-content"><%= content %></label>
      <button class="todo-destroy"></button>
    </div>
    <input class="edit" value="<%= content %>">
  </li>
</script>

User Authentication

We've extended the typical todo app with user authentication, which allows you to login and manage your todo items from multiple devices. Fortunately, adding this functionality is a breeze with Parse.

First, we create a main view called AppView which will manage 2 subviews: the LoginView and ManageTodosView. Basically, we've now added a login screen in front of the usual todo app. We simply test to see if there is a logged in user to determine which view to show:

if (Parse.User.current()) {
  new ManageTodosView();
} else {
  new LogInView();
}

The login view shows two forms, one to login and one to sign up for a new account:

<form class="login-form">
  <h2>Log In</h2>
  <div class="error" style="display:none"></div>
  <input type="text" id="login-username" placeholder="Username" />
  <input type="password" id="login-password" placeholder="Password" />
  <button>Log In</button>
</form>
<form class="signup-form">
  <h2>Sign Up</h2>
  <div class="error" style="display:none"></div>
  <input type="text" id="signup-username" placeholder="Username" />
  <input type="password" id="signup-password" placeholder="Create a Password" />
  <button>Sign Up</button>
</form>

The view binds to the submit event for both these forms and logs in or signs up the user, respectively. The login code looks like:

Parse.User.logIn(username, password, {
  success: function(user) {
    new ManageTodosView();
    self.undelegateEvents();
    delete self;
  },
  error: function(user, error) {
    self.$(".login-form .error").html("Invalid username or password. Please try again.").show();
    this.$(".login-form button").removeAttr("disabled");
  }
});

Once the user logs in, the Parse SDK automatically handles maintaining the session so that Parse.User.current() will always be an instance of the user that is logged in. We immediately show the ManageTodosView after log in.

The sign up code looks similar:

Parse.User.signUp(username, password, { ACL: new Parse.ACL() }, {
  success: function(user) {
    new ManageTodosView();
    self.undelegateEvents();
    delete self;
  },
  error: function(user, error) {
    self.$(".signup-form .error").html(error.message).show();
    this.$(".signup-form button").removeAttr("disabled");
  }
});

This creates the account with the given username and password from the fields and also applies a blank ACL on the user. This prevents anyone from reading data from the User class unless they are the user who is logged in.

In both of these views, we handle errors by displaying the error message in a div upon callback.

Persisting the Todo Items

The rest of the application is very similar to the original Backbone.js todo app. You can read through the original annotated source to get a sense of how Backbone Models and Collections are used to represent the todo items.

The major change that we applied was to swap out our Parse classes in place of the Backbone classes, like so:

var Todo = Parse.Object.extend("Todo", {
  // ...
});
var TodoList = Parse.Collection.extend({
  // ...
});

This automatically makes the Todo model persist itself to the Parse platform, instead of to local storage like in the original app. You can read more about converting existing Backbone apps to Parse here.

The only other part of the app that required a change was in how we populate the collection of todo items. Here, we construct a Parse.Query to obtain all the todo items that are owned by this user and set it to the query for the TodoList instance:

// Create our collection of Todos
this.todos = new TodoList;

// Setup the query for the collection to look for todos from the current user
this.todos.query = new Parse.Query(Todo);
this.todos.query.equalTo("user", Parse.User.current());

// ...

// Fetch all the todo items for this user from Parse
this.todos.fetch();

And that's it. Now, whenever a todo item is saved, deleted, or created, the state is persisted to Parse.