Srikanth Technologies

Todos List with IndexedDB

In this blog, I develop a Single Page Application(SPA) that allows user to maintain his/her own todo list.

It uses IndexedDB feature of HTML5 to store todo list. IndexedDB allows JavaScript objects to be stored in a Store, which is part of Database.

What do we use?

The following are the features and libraries used in this application.

Make sure you place jquery.js, jquery-ui.js and jquery-ui.css files in jquery folder to make them available to this page.

Code

Here is the code in todoslist.html, for our Single Page Application. This page contains JavaScript to use IndexedDB and jQuery.

<!Doctype HTML>
<html>
<head>
    <title>Todos List</title>
    <style>
        h2 { background-color:red; color:white}
        table.todos  {
             border-spacing : 5px;
             padding :5px;
             width :100%;
        }
        table.todos tr th  {
            background-color:blue; color:white;
        }
        table.todos tr td,th {
                text-align: center;
        }
        #divUpdate { visibility : hidden }
    </style>
    <link href="jquery/jquery-ui.css" rel="stylesheet" />
    <script src="jquery/jquery.js"></script>
    <script src="jquery/jquery-ui.js"></script>
</head>
<body>
    <h2>Todos</h2>
    <script type="text/javascript">
        var db;
        var databasename = "todo";
        var storename = "todos";
        $(function () {
            openDb();
            $("#txtDate").datepicker(
                    {
                        dateFormat: "yy-mm-dd", changeMonth: true,
                        changeYear: true,
                        showAnim: "fold", showButtonPanel: true
                    });
        });

        function openDb() {
            var request = indexedDB.open(databasename, 4);
            request.onerror = function (event) {
                alert("Sorry! Browser doesn't support required features!");
            };
            request.onsuccess = function (event) {
                db = event.target.result;
                listTodos();
            };

            request.onupgradeneeded = function (event) {
                var newversion = event.target.result;
                if (!newversion.objectStoreNames.contains(storename)) {
                    var store = newversion.createObjectStore(storename, { autoIncrement: true });
                    var index = store.createIndex("dateindex", "date", { unique: false });
                }
            }
        }

        function editTodo(key) {
            var transaction = db.transaction([storename], "readonly");
            var store = transaction.objectStore(storename);
            var getRequest = store.get(key);

            getRequest.onsuccess = function (event) {
                var todo = event.target.result;
                if (todo !== undefined) {
                    $("#txtText").val(todo.text);
                    $("#txtDate").val(todo.date);
                    $("#key").val(key);
                    // show relevant buttons
                    $("#divUpdate").css("visibility", "visible");
                    $("#btnAdd").hide();
                }
            };
        }

        function cancelEdit() {
            $("#txtText").val("");
            $("#txtDate").val("");
            // hide and show  relevant buttons
            $("#divUpdate").css("visibility", "invisible");
            $("#btnAdd").show();
        }

        function addTodo() {
            var text = $("#txtText").val();
            if (text == "") {
                alert("Please enter text for todo!");
                return;
            }
            var date = $("#txtDate").val();
            if (date == "") {
                alert("Please enter date for todo!");
                return;
            }

            var todo = { text: $("#txtText").val(), date: $("#txtDate").val() };

            var transaction = db.transaction([storename], "readwrite");
            var store = transaction.objectStore(storename);
            var addrequest = store.add(todo);

            addrequest.onsuccess = function (event) {
                listTodos();
            };

            addrequest.onerror = function (event) {
                alert("Could not add todo!");
            };
        }

        function deleteTodo(key) {
            var resp = confirm("Do you really want to delete todo??");
            if (!resp)
                return;

            var transaction = db.transaction(storename, "readwrite");
            var store = transaction.objectStore(storename);
            var deleteRequest = store.delete(key);

            deleteRequest.onsuccess = function (event) {
                listTodos();
            };
        }

        function updateTodo() {
            var todo;
            var key = Number($("#key").val());
            var transaction = db.transaction(storename, "readwrite");
            var store = transaction.objectStore(storename);
            var getRequest = store.get(key);

            getRequest.onsuccess = function (event) {
                todo = event.target.result;
                // now modify the name and date 
                todo.text = $("#txtText").val();
                todo.date = $("#txtDate").val();

                var putRequest = store.put(todo, key)
                putRequest.onsuccess = function (e) {
                    listTodos();
                    cancelEdit();
                }
            };
        }

        function listTodos() {
            var list = "";
            var todo;
            var transaction = db.transaction(storename, "readonly");
            var store = transaction.objectStore(storename);
            var index = store.index("dateindex");
            var cursor = index.openCursor();

            cursor.onsuccess = function (event) {
                todo = event.target.result;
                if (todo != null) {
                    list += "<tr><td><button onclick='deleteTodo(" + todo.primaryKey + 
                                        ")'>Delete</button> <button onclick='editTodo(" + todo.primaryKey + 
                                        ")'>Edit</button></td>"
                    list += "<td>" + todo.value.date + " </td><td>" + todo.value.text + "</td></tr>";
                    todo.continue();
                }
                else {

                    if (list === "")
                        $("#todosList").html("No todos found!");
                    else
                        $("#todosList").html("<table class='todos'><tr><th>Action</th><th>Date</th><th>Task</th></tr>" 
                                 + list + "</table>");
                }
            };

        }
    </script>

    <h3>New Todo</h3>
    <input type="text" id="txtText" placeholder="text"  size="50"/>
    <p/>
    <input type="text" id="txtDate" placeholder="date (yyyy-mm-dd)" />
    <p/>
    <input type="hidden" id="key" />
    <p/>
    <input type="button" id="btnAdd"  onclick="addTodo()" value="Add Todo" />

    <div id="divUpdate">
        <input type="button" id="btnUpdate" onclick="updateTodo()" value="Update" />
        <input type="button" id="btnCancel" onclick="cancelEdit()" value="Cancel" />
    </div>

    <h3>Todos List</h3>
    <div id="todosList"></div>

</body>
</html>

    
You can test this application at http://www.srikanthtechnologies.com/todoslist.html"