Todo Example with Angularjs and Persistencejs

In the world of JavaScript frameworks, it appears the Todo app has become the new Hello World. I came up with the idea a while ago seemingly on my own, because I thought it would make a nice, easy to understand way to showcase the particular stack of libraries I have been using. Perhaps it is the collective consciousness, but as I started working on my demo, I noticed a few others doing the same.

Tobias Bosch and Christoph Burgdorf have both been working with Todo examples using the angular.js library which I have recently fallen in love with. Then came Addy Osmani, who runs a slick website/web-dev ninja training academy. Addy came up with the brilliant idea to package a number of demos from various JavaScript MVC frameworks all based around the same design. Naturally, the demo of choice was Todo.

Addy used Christoph’s Angularjs app in his TodoMVC package. I forked TodoMVC and made a copy of the Angularjs example. I added to this example a service which stores the todo list in a local database in the browser using persistence.js.

In a nutshell, Angularjs works by binding html elements with a JavaScript controller. The controller holds the data objects that are linked to html as well as any methods that may be triggered by the webpage. Controllers can be enhanced by injecting services, which supply specific additional functionality.

Persistencejs is a framework that provides an abstraction layer for local storage in the browser. I have been using it to create WebSQL databases for mobile projects. It also has a plugin for synchronization through Node.js.

My change to the Angularjs Todo example was to add a service which wrapped all the Persistencejs functionality. The example still works the same, but any time you add, edit or remove items, it makes an additional call to the Persistencejs service. Additionally, when first loaded, the controller is able to fetch any locally stored items to pre-populate the page.

The working demo can be viewed here: http://jacobmumm.com/demos/todo/. Below, I are some highlights of the changes.

First, it was necessary to create an Angularjs service to handle the Persistencejs calls. The way Angularjs services are defined is in the singleton pattern. The constructor is a factory that produces a usable object, and it is during this time that I can setup the local database.

This is what the service looks like.

angular.service('persistencejs', function() {
	persistence.store.websql.config(persistence,
 'todo', 'todo database', 5*1024*1024);
	var Todo = persistence.define('todo', {
		content: 'TEXT',
		done: 'BOOL'
	});
	persistence.schemaSync();
	return {
                //singleton containing all methods to be called
        };

The controller is now declared with a parameter, expecting the service to be injected afterward.

App.Controllers.TodoController = function (persistencejs) {/*...*/};
App.Controllers.TodoController.$inject = ['persistencejs'];

Within the TodoController, methods can now properly call methods in the persistencejs service:

//in TodoController:
  self.addTodo = function() {
      if (self.newTodo.length === 0) return;

      self.todos.push({
          content: self.newTodo,
          done: false,
          editing: false
      });
      //below is the only change I made to this method
      //I only need to know the content, because
      //it can be assumed new items are not done yet
      persistencejs.add(self.newTodo);

      self.newTodo = "";
  };

//in the persistencejs service:
add: function(item){
	var t = new Todo();
	t.content = item;
	t.done = false;
	persistence.add(t);
	persistence.flush();
},

One critical caveat I must mention here applies to the situation where Angularjs data gets modified asynchronously. If you modify data within controller methods, the automatic data binding will trigger the page to be refreshed. However, this is not the case when the data gets updated asynchronously. Persistencejs is an asynchronous library, so every interaction happens this way. Fortunately, there is a simple solution. Anytime you have made such asynchronous manipulations, you simply need to call the $apply method on your controller.

This entry was posted in Javascript and tagged , . Bookmark the permalink.

Comments are closed.