Linking IndexedDB and JQuery: How to delete a table row by targeting the table data in a selected row?

Viewed 265

I'm trying to link my jQuery table with IndexedDB (IDB). Currently, I'm able to add items to the browser UI and to IDB successfully, which generates an identifier key. When the item is pulled from IDB I've stored the identifier key in a hidden column at the furthest right of the table (see screenshot) for each item.

What I want to do is delete the item from the UI and IDB. My code from line 26 of the main.js (bottom-right in screenshot) is successfully deleting the item from the UI, however the code at line 32 isn't deleting the item from IDB as required.

I've run both an alert/console.log for the variable (line 34) which is reporting the correct key identifier has been stored in the variable, but seems to be functioning unusually in that it is reporting it multiple times based on which row is selected in the table (i.e. if I delete "exercise" it reports 36 on three separate alerts?). The variable is then not correctly deleted. However, if I run line 35 and pass the literal key identifier into it (i.e. "36") instead of a variable, the item is deleted.

Any suggestions would be really welcome, thank you!

Screenshot[1]

Table and code https://i.stack.imgur.com/Etb2S.png

Full code available here (please note I've included all separate files on the JS page) https://codepen.io/QuiveringCoward/pen/gOMqpRv

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>jQuery Add / Remove Table Rows</title>
        <!-- link to CSS-->
        <link rel="stylesheet" href="./style.css">
        <!-- link to JQuery-->
        <script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
        
        <!--link to JS-->
        <script src="./main.js"></script>
        <script src="../lib/indexedDB.js"></script>
    </head>
<body>
    <!-- user inputs for tasks -->
    <h1> Simplicity | Simplify Your Life </h1>
    <form id="todo-list">
        
        <label for=task>Task</label>
        <input type="text" id="task" placeholder="Task" required="required">
        
        <label for=task>Description</label>        
        <input type="text" id="description" placeholder="Description">
        
        <label for=task>Due Date</label>        
        <input type="date" id="date" placeholder="Due Date" required="required">
        
        <label for=task>Time</label>        
        <input type="time" id="time" placeholder="00:00">

        <label for=task>Frequency</label>        
        <select id="frequency" name="frequency" class="todo-frequency">
            <option value="Daily">Daily</option>
            <option value="Weekly">Weekly</option>
            <option value="Monthly">Monthly</option>
        </select>
        
        <label for=task>Location</label>        
        <input type="text" id="location" name="location" placeholder="Location">
        
        <label for=task>Priority</label>        
        <select id="priority" name="priority" class="todo-priority">
            <option value="1-high">1 - High</option>
            <option value="2-medium">2 - Medium</option>
            <option value="3-low">3 - Low</option>
        </select>
        
        <br>
        <br>
          <!-- add task button -->  
        <input type="submit" class="add-task" value="Add Task">
        <br>
        <br>
        <label for=search>Search Table</label>
        <input type="text" id="search" placeholder="Search here...">

    </form>
    <h2>Todo List</h2>
    <table id="todo-table">
        <!-- headers for todolist-->
        <thead> 
            <tr>
                <th>Select</th>
                <th>Task</th>
                <th>Description</th>
                <th>Due Date<span> &#8597;</span></th>
                <th>Time</th>
                <th>Frequency</th>
                <th>Location</th>
                <th>Priority<span> &#8597;</span></th>
                <th class="key" id="key"></th>
            </tr>
        </thead>
        <tbody>
            <!-- where the JS will append the tasks -->
        </tbody>
    </table>
    <!-- submit button for todolist -->
    <button type="button" class="delete-task">Delete Task(s)</button>
    <br>
    <br>
    <button type="button" id="all-tasks">All Tasks</button>
    <button type="button" id="daily-tasks">Daily Tasks</button>
    <button type="button" id="weekly-tasks">Weekly Tasks</button>
    <button type="button" id="monthly-tasks">Monthly Tasks</button>

    <script src="./AddItemPage/AddItem.js"></script>
    <script src="./AddItemPage/AddItemDAO.js"></script>
    <script src="./ListItemsPage/ListItems.js"></script>
    <script src="./ListItemsPage/ListItemsDAO.js"></script>
    
</body> 
</html>
//*************** OTHER PAGES STORED LOCALLY **************//

// AddItem.js
$("#todo-list").submit(function(event){

    event.preventDefault();

    setDatabaseName("Luke's Todo List", ["UsersObjectStore", "ItemsObjectStore"]);

    setCurrObjectStoreName("ItemsObjectStore");

    startDB(function () {
        saveItemData();
        alert("Item has been saved successfully!");
    })
})

// AddItemDAO.js

function saveItemData() {


    var data = {

    };

    insertOne(data, function(lastID){
        event.preventDefault();
        return false;
    });

}

// ListItems.js
setDatabaseName("Luke's Todo List", ["UsersObjectStore", "ItemsObjectStore"]);
setCurrObjectStoreName("ItemsObjectStore");
startDB(function() {
    showAllItems();
});

//ListItemsDAO.js
function showAllItems() {
    selectAll(function(results) {
        var len = results.length, i;

        for(i = 0; i < len; i++) {
            $("#todo-table").append(
                '<tr id="' + results[i].id +'" class="' + results[i].frequency + " " + results[i].priority +'">\
                    <td> <input type="checkbox" name="record"></td>\
                    <td class="task">' + results[i].task + '</td>\
                    <td class="description">' + results[i].description + '</td>\
                    <td class="date">' + results[i].date + '</td>\
                    <td class="time">' + results[i].time + '</td>\
                    <td class="frequency">' + results[i].frequency + '</td>\
                    <td class="location">' + results[i].location + '</td>\
                    <td class="priority">' + results[i].priority + '</td>\
                    <td class="key" id="key">' + results[i].id + '</td>\
                 </tr>'
            )
        }
    });
}

// Indexed DB library wrapper

    //This is an indexeddb wrapper javascript library
    
    //Global variables
    var db, indexedDB, IDBTransaction, currObjectStoreName, databaseName, objectStores;
    
    //startDB creates connection with the databaseName
    //and create database and object stores
    function startDB(successCallback, failureCallback) {
        try {
            indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
            IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
            IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
        }
        catch(e) {
            console.log('Initial IndexedDB error: ' + e);
            failureCallback();
        }
        
        if(!window.indexedDB) {
            failureCallback();
            return;
        }

        var request = indexedDB.open(databaseName, 1);
            
        //The onupgradeneeded property is triggered when a database 
        //of a bigger version number than the existing stored database is loaded.
        request.onupgradeneeded = function(event) {
            console.log('onupgradeneeded method is invoked');
            db = event.target.result;
            for(i=0; i < objectStores.length; i++) {
                db.createObjectStore(objectStores[i], { keyPath: 'id', autoIncrement: true });
            }
        };

        request.onsuccess = function(event) {
            db = event.target.result;
            successCallback && successCallback();
        };

        request.onerror = function(event) {
            console.log('User don\'t allow IndexedDB to use offline storage.');
            failureCallback();
        };
    }

    //Just print any indexeddb related error message in console window
    function indexedDBError(event) {
        console.log('An error occurred in IndexedDB', event);
    }
    
    //setDatabaseName sets the Database name and Object Stores required for a website
    function setDatabaseName(dbName, objStores) {
        databaseName = dbName;
        objectStores = objStores;
        console.log('Database : ', dbName);
    }
    
    //setCurrObjectStoreName set the current object store to store or retrieve data
    function setCurrObjectStoreName(objStoreName) {
        currObjectStoreName = objStoreName;
        console.log('Current Object Store Name : ', currObjectStoreName);
    }

    //selectAll retrieves all data from the current object store
    function selectAll(successCallback) {
        var transaction = db.transaction([currObjectStoreName], IDBTransaction.READ_ONLY || 'readonly'),
            objectStore, request, results = [];
            
        transaction.onerror = indexedDBError;
        objectStore = transaction.objectStore(currObjectStoreName);
        request = objectStore.openCursor();

        request.onerror = indexedDBError;
        request.onsuccess = function(event) {
            // event.target means request
            var cursor = event.target.result;
            if(!cursor) {
                if(successCallback) {
                    successCallback(results);
                }
                return;
            }
            results.push(cursor.value);
            cursor.continue();
        };
    }
    
    //insertOne inserts data into the current object store
    //This function also creates unique id for each data
    function insertOne(data, successCallback) {
        var transaction = db.transaction([currObjectStoreName], IDBTransaction.READ_WRITE || 'readwrite'),
            objectStore, request, lastID;
        
        objectStore = transaction.objectStore(currObjectStoreName);
        request = objectStore.add(data);
        request.onsuccess = function(event) {
            lastID = event.target.result;
        }
        request.onerror = indexedDBError;
        
        transaction.onerror = indexedDBError;

        transaction.oncomplete = function(event) {
            console.log('Data was inserted succesfully');
            if(successCallback) {
                successCallback(lastID);
            }
        };
    }
    
    //deleteOne inserts data into the current object store
    function deleteOne(id, successCallback) {
        var transaction = db.transaction([currObjectStoreName], IDBTransaction.READ_WRITE || 'readwrite'),
            objectStore, request;
            
        objectStore = transaction.objectStore(currObjectStoreName);
        request = objectStore.delete(id);
        request.onerror = indexedDBError;
        request.onsuccess = function(event) {
            var result = event.target.result;
        };
        transaction.onerror = indexedDBError;
        transaction.oncomplete = function() {
            console.log('Data with ' + id + ' was deleted successfully');
            if(successCallback) {
                successCallback();
            }
        };
    }
    
    //updateOne updates a specific data in the current object store
    function updateOne(data, successCallback) {
        var transaction = db.transaction([currObjectStoreName], IDBTransaction.READ_WRITE || 'readwrite'),
            objectStore, request, lastID;
        
        objectStore = transaction.objectStore(currObjectStoreName);
        request = objectStore.put(data);
        request.onsuccess = function(event) {
            lastID = event.target.result;
        }
        request.onerror = indexedDBError;
        
        transaction.onerror = indexedDBError;

        transaction.oncomplete = function(event) {
            console.log('Data with ' + lastID + ' was deleted successfully');
            if(successCallback) {
                successCallback(lastID);
            }
        };
    }
    
    //selectOne select just one data
    function selectOne(id, successCallback) {
        var transaction = db.transaction([currObjectStoreName], IDBTransaction.READ_ONLY || 'readonly'),
            objectStore, request;
            
        transaction.onerror = indexedDBError;
        objectStore = transaction.objectStore(currObjectStoreName);
        request = objectStore.get(parseInt(id));

        request.onerror = indexedDBError;
        request.onsuccess = function(event) {
            // event.target means request
            
            var record = request.result;
            
            if(record) {
                
                if(successCallback) {
                    
                    successCallback(record);
                }
                return;
            }
        };
    }
    
1 Answers

I discovered that there's also a function that you can call to delete the data from IndexedDB, it's called deleteOne() and all you have to do is find the key of the data that needed to be deleted. I solved it with this code

$("table tbody").find('input[name="record"]:checked').each(function() {
     deleteOne(parseInt($(this).closest('tr')[0].id))
});
Related