0

I created a little app which allows you to add and delete todo's to a list. Because I wanted to share these data with other devices I wrote a little export function to export the data as JSON and import them as well.

However, the import mostly imports only the last item in the list, sometimes more, but never all the data.

Based on advice here on the website I created a function which loops through the todo list everytime the put has been successful, but it still doesn't give the desired result.

edu.indexedDB.importTodos = function(todos) {       
        var db = edu.indexedDB.db;      
        var transaction = db.transaction(['todo'], 'readwrite');        
        var objStore = transaction.objectStore('todo');
        var i = 0;
        putNext();      
        function putNext() {            
            if (i<todos.length) {               
                var tmpResult = eval('('+todos[i]+')');     
                var text = tmpResult.text;
                var timestamp = new Date().getTime();
                var todo = {'text': text,'timestamp': timestamp};
                console.log("adding " + text);
                objStore.put(todo).onsuccess = putNext;
                ++i;
            } else {                           
                edu.indexedDB.getAllTodoItems();
            }
        }      
    };

The complete app basic code:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <style>
        a{cursor:pointer;}
    </style>
    <script>
    var todoContainer = document.getElementById("todo-container");
    var edu = {};   
    var exportObj = {};
    exportObj['todo'] = {};
    var todoArray = new Array();

    window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;

    if ('webkitIndexedDB' in window) {
        window.IDBTransaction = window.webkitIDBTransaction;
        window.IDBKeyRange = window.webkitIDBKeyRange;
    }

    edu.indexedDB = {};
    edu.indexedDB.db = null;

    edu.indexedDB.onerror = function(e) {
      console.log(e);
    };

    edu.indexedDB.open = function(callback) {
        var version = 2;
        var request = indexedDB.open("edudb-dev1",version);

        request.onupgradeneeded = function(e) {
            var db = e.target.result;

            e.target.transaction.onerror = edu.indexedDB.onerror;
            //todo datastore
            if (db.objectStoreNames.contains('todo')) {
              db.deleteObjectStore('todo');
            }
            var store = db.createObjectStore('todo', {
              keyPath: 'timestamp'
            }); 
        };

        request.onsuccess = function(e) {          
            edu.indexedDB.db = e.target.result;
            var db = edu.indexedDB.db;      
            callback();
        };
        request.onerror = edu.indexedDB.onerror;
    };

    edu.indexedDB.addTodo = function(todoText) {        
        var db = edu.indexedDB.db;      
        var transaction = db.transaction(['todo'], 'readwrite');        
        var objStore = transaction.objectStore('todo');     
        var timestamp = new Date().getTime();       
        var todo = {'text': todoText,'timestamp': timestamp};       
        var request = objStore.put(todo);           
        request.onsuccess = function(e) {       
            edu.indexedDB.getAllTodoItems();        
        };
        request.onerror = function(e) {
            console.log("Error Adding: ", e);
        };
    };
    edu.indexedDB.deleteTodo = function(id) {
        var db = edu.indexedDB.db;
        var transaction = db.transaction(['todo'], 'readwrite');
        var objStore = transaction.objectStore('todo');

        var request = objStore.delete(id);

        request.onsuccess = function(e) {
            edu.indexedDB.getAllTodoItems();
        }
        request.onerror = function(e) {
            console.log(e);
        }
    };
    edu.indexedDB.getAllTodoItems = function() {
        var todos = document.getElementById("todoItems");
        todos.innerHTML = "";      
        var db = edu.indexedDB.db;
        var trans = db.transaction(["todo"], "readwrite");
        var store = trans.objectStore("todo");

        // Get everything in the store;
        var cursorRequest = store.openCursor(); 
        cursorRequest.onsuccess = function(e) {         
          var result = e.target.result;
          if(!result)
            return;
          renderTodo(result.value);
          result.continue();
        };  
        cursorRequest.onerror = edu.indexedDB.onerror;
    };
    function renderTodo(row) {  
        var todos = document.getElementById("todoItems");
        var li = document.createElement("li");
        var a = document.createElement("a");
        var t = document.createTextNode(row.text);      
        var timestamp = row.timestamp;
        a.addEventListener("click", function() {
          edu.indexedDB.deleteTodo(timestamp);
        }, false);      
        a.textContent = " [Delete]";
        li.appendChild(t);
        li.appendChild(a);
        todos.appendChild(li);
        //exportobject
        addToExport("todo",JSON.stringify(row));    
    }
    function addTodo() {
        var todo = document.getElementById("todo");     
        if(todo.value){
            edu.indexedDB.addTodo(todo.value);
            todo.value = "";
        }else{
            showNotification("Please enter a todo description.");
        }        
    }
    function init() {
        edu.indexedDB.open(refresh);        
    }

    function refresh(){
        edu.indexedDB.getAllTodoItems();
    }

    function showNotification(message){
        notification.style.display = 'block';
        notification.innerHTML = message;
    }
    function addToExport(type,row){             
        switch(type){
            case 'todo':
                todoArray.push(row);
                exportObj['todo'] = todoArray;
                break;
        }       
    }
    function showExport(){      
        document.getElementById("data").value = JSON.stringify(exportObj);
    }
    //imports
    function importData(){      
        var importData = document.getElementById("data").value;     
        var parsedJSON = eval('('+importData+')');              
        var dataTodo = parsedJSON.todo;
        edu.indexedDB.importTodos(dataTodo);
    }
    edu.indexedDB.importTodos = function(todos) {       
        var db = edu.indexedDB.db;      
        var transaction = db.transaction(['todo'], 'readwrite');        
        var objStore = transaction.objectStore('todo');
        var i = 0;
        putNext();      
        function putNext() {            
            if (i<todos.length) {               
                var tmpResult = eval('('+todos[i]+')');     
                var text = tmpResult.text;
                var timestamp = new Date().getTime();
                var todo = {'text': text,'timestamp': timestamp};
                console.log("adding " + text);
                objStore.put(todo).onsuccess = putNext;
                ++i;
            } else {                           
                edu.indexedDB.getAllTodoItems();
            }
        }      
    };
    window.addEventListener("DOMContentLoaded", init, false);
    </script>
</head>
<body>
    <nav>
        <div id="menu">
            <a id="menu-todo" class="menu-item" onclick="showContainer('todo'); return false;">TODO</a>
            <a id="menu-export" class="export-item" onclick="showExport(); return false;">export</a>
            <a id="menu-import" class="import-item" onclick="importData(); return false;">import</a>    
        </div>
    </nav>
    <div id="container">
        <!-- todo -->
        <div id="todo-container">
            <h4>Todo's</h4>
            <ul id="todoItems"></ul>
            <form id="todo-form">
                <input type="text" id="todo" name="todo" placeholder="Enter todo..." />
                <input type="submit" value="+" class="btn" onclick="addTodo(); return false;"/>
            </form>
        </div>
    </div>
    <nav>
    </nav>
    <textarea id="data" style="width:98%;height:250px;"></textarea>
    <div id="notification"></div>
    <div id="footer">&copy;</div>
</body>
</html>
randomizer
  • 1,619
  • 3
  • 15
  • 31

1 Answers1

0

You don't have to wait for the put to be successfull to continue, you can just loop your collection and add them. Then you can detect if the inserts are successfull by using the complete call back on the transaction. In this you can then start a new readonly transaction to retrieve all data.

Kristof Degrave
  • 4,142
  • 22
  • 32
  • My original code didn't have this way of looping, but I altered my code to make it work based on this thread http://stackoverflow.com/questions/10471759/inserting-large-quantities-in-indexeddbs-objectstore-blocks-ui so is this incorrect? I still don't understand why my code doesn't work? What exactly do you mean using the complete callback on the transaction? The "oncomplete" ? I'm a noob on indexeddb :) – randomizer Sep 24 '13 at 09:37