0

I am new to Index DB, so this might be a simple fix, but I can't seem to find any fix for it in my code. I am using live server to display it, and the problem I'm facing is that it is supposed to display the total Money in the html, but it is giving me an error in the console: Here. Thank you for your consideration

Below here is my dbFunctions. js

let db;
let request = indexedDB.open("financeManager", 1);




request.onupgradeneeded = function(event){
    db = event.target.result;
    db.createObjectStore("expenses", { keyPath:'id', autoIncrement: true});
    db.createObjectStore("incomes", {keyPath: 'id', autoIncrement: true});
    db.createObjectStore("totalMoney", {keyPath: 'id', autoIncrement: true});

    

};

if(!db.objectStoreNames.contains("totalMoney")){

}


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

request.onerror = function(event){
    console.log('error', event.target.errorCode);
};


function updateTotalMoney(updatedTot){
    var transaction = db.transaction(['totalMoney'], 'readwrite');
    var objectStore = transaction.objectStore('totalMoney');

    var getTotal = objectStore.get(1);
    
    getTotal.onsuccess = function(event){
        var data = event.target.result;
        if(data){
            data.total = updatedTot;
            var updateRequest = objectStore.put(data);
            
            updateRequest.onsuccess = function(){
                console.log('Successfully Updated Total');
            }
            updateRequest.onerror = function(){
                console.log("Error with Updating: ", event.target.error);
            }


        } else{
            console.log("no existing totalMoney found, please initialize it first before updating");
        }
        
    }

    getTotal.onerror = function(event){
        console.log("error retrieving Total: ", event.target.error);
    }
}


//GetDatabyname funciton essentially
function getDataByName(storeName, nameValue, callback){
    let transaction = db.transaction([storeName], 'readonly');
    let objectStore = transaction.objectStore(storeName);

    let result = [];

    objectStore.openCursor().onsuccess = function(event){
        let cursor = event.target.result;
        if(cursor){
            if(cursor.value.name === nameValue){
                result.push(cursor.value);
            }
            cursor.continue();
        } else{
            callback(result);
        }
    }
}
//should only be used once, adds totalMoney as a db 
function initializeTotalMoney(total){
    var transaction = db.transaction(['totalMoney'], 'readwrite');
    var objectStore = transaction.objectStore('totalMoney');

    var totalMoney = {
        'total': total
    };
    var request = objectStore.add(totalMoney);

    request.onsuccess = function(event){
        console.log("Successfull");
    }

    request.onerror = function(event){
        console.log("error adding total:" ,event.target.error);
    }
}
function checkAndInitializeTotalMoney(InitialValue){
    var transaction = db.transaction(['totalMoney'], 'readonly');
    var objectStore = transaction.objectStore('totalMoney');

    var getRequest = objectStore.get(1);

    getRequest.onsuccess = function(e){
        if (!e.target.result){
            initializeTotalMoney(InitialValue);
        } else{
            console.log("totalMoney already initialized: ", e.target.result);
        }
    };
    getRequest.onerror = function(e){
        console.log("Error checking tot money: ", e.target.error);
    };
}


//db boilerplate function to add an expense, use addExpense with a name and amount
function addExpense(name, amount, type, interestRate = 0, importance = "N/A"){
    var transaction = db.transaction(['expenses'], 'readwrite');

    var objectStore = transaction.objectStore('expenses');

    var expense = {
        'name': name,
        'amount': amount,
        'interestRate': interestRate,
        'type': type,
        'date': new Date(),
        'importance': importance
    };

    var request = objectStore.add(expense);

    request.onsuccess = function(event){
        console.log('Successfully added Expense');
    }

    request.onerror = function(event){
        console.log('Error adding Expense: ', event.target.error);
    };

}

function addIncome(name, amount, type, interestRate = 0, frequency = "N/A"){
    var transaction = db.transaction(['incomes'], 'readwrite');

    var objectStore = transaction.objectStore('incomes');

    var income = {
        'name': name, 
        'amount': amount,
        'type': type,
        'interestRate': interestRate,
        'date': new Date(),
        'frequency': frequency
    };

    var request = objectStore.add(income);

    request.onsuccess = function(event){
        console.log('Successfully added Income');

    }

    request.onerror = function(event){
        console.log('Error adding Income: ', event.target.error);
    };



}

Below is addIncome. js and addIncome. html

const dropdownIncome = document.getElementById("dropdownIncome");
const optionForms = document.querySelectorAll(".options");

//submit btns form
const submitOneTime = document.getElementById("submitOneTime");
const submitMonthly = document.getElementById("submitMonthly");
const submitInterest = document.getElementById("submitInterest");

//oneTimeInput
const oneTimeInputLabel = document.getElementById("oneTimeInputLabel");
const oneTimeInput = document.getElementById("oneTimeInput");
//monthlyInput
const monthlyInputLabel = document.getElementById("monthlyInputLabel");
const monthlyInput = document.getElementById("monthlyInput");
const radiosMonthly = document.getElementsByName("radioMonthlyIncome");
//interestInput
const interestInputLabel = document.getElementById("interestInputLabel");
const interestInput = document.getElementById("interestInput");
const interestRateInput = document.getElementById("interestRateInput");

//ultimately displays the selected item of the dropdown
dropdownIncome.addEventListener("change", function(){
    const selectedOption = this.value;
    const showForm = document.getElementById(selectedOption);
    //makes each form invisible
    optionForms.forEach(form => {
        form.style.display = 'none';
    });
    //shows the selected form
    showForm.style.display = "block";

});


//ultimately adds data in input to db and updates totalMoney
submitOneTime.addEventListener("click", function(){
    let oneTimeInputValue = parseFloat(oneTimeInput.value);
    if(isNaN(oneTimeInputValue)){
        alert("Please Enter A Number");
    }
    else{
        //defines expenseName and expenseAmount to be put into addExpense
        var incomeName = oneTimeInputLabel.value;
        var incomeAmount = oneTimeInputValue;

        //adds the name and amount into the db
        addIncome(incomeName, incomeAmount, "oneTime");

        getDataByName("totalMoney", "total", function(data){
            if (data && data[0]){
                var currentTotal = data[0].total;
                var newTotal = currentTotal + oneTimeInputValue;
                updateTotalMoney(newTotal);
            } else{
                console.log("Error retreiving total Money");
            }
        });
        
}});

//ultimately adds data in input to db
submitMonthly.addEventListener("click", function(){
    let monthlyInputValue = parseFloat(monthlyInput.value);
    if(isNaN(monthlyInputValue)){
        alert("Please Enter A Number");
    }
    else{
        for (var i=0, length=radiosMonthly.length; i < length; i++){
            if(radiosMonthly[i].checked){
                var selected = radiosMonthly[i];
                break;
            }
        }

        //defines expenseName and expenseAmount to be put into addExpense
        var incomeName = monthlyInputLabel.value;
        var incomeAmount = monthlyInputValue;
        var incomeFrequency = selected.value;

        //adds the name and amount into the db
        addIncome(incomeName, incomeAmount, "monthly", undefined, incomeFrequency);
        //ADD UPDATETOTALMONEY HERE, DEPENDING ON inCOME FREQUENCY//
    
}});

submitInterest.addEventListener("click", function(){
    let interestInput = parseFloat(interestInput.value);
    let interestRateInput = parseFloat(interestRateInput.value);

    if(isNaN(interestInput) || isNaN(interestRateInput)){
        alert("Please enter numbers for both inputs");

    }
    else{
        var incomeName = interestInputLabel.value;
        var incomeAmount = interestInput;
        var incomeInterest = interestRateInput;

        addIncome(incomeName, incomeAmount, "interest", incomeInterest);

    }
});
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <select id="dropdownIncome">
        <option value="default">--</option>
        <option value="optionOneTime">
            One-Time Income
        </option>
        <option value="optionMonthly">
            Monthly Income
        </option>
        <option value="optionInterest">
            Interest Income
        </option>


    </select>
    <div id="default" class="options" style="display:none;"> </div>
    <div id="optionOneTime" class = "options" style="display:none;">
        <input type = "text" placeholder="Label" id="oneTimeInputLabel">
        <input type= "text" placeholder="Enter your One-Time Income" id ="oneTimeInput">
        <button id="submitOneTime" class="btnIncome">Submit</button>
        

    </div>
    <div id="optionMonthly" class="options" style="display:none;">
        <input type = "text" placeholder="Label" id="monthlyInputLabel">
        <input type="text" placeholder="Enter your Monthly Income" id="monthlyInput">
        <button id="submitMonthly" class="btnIncome">Submit</button>
        <input type="radio" name="radioMonthlyIncome" id="Weekly">Weekly
        <input type="radio" name="radioMonthlyIncome" id="BiWeekly">Bi-Weekly
        <input type="radio" name="radioMonthlyIncome" id="Monthly">Monthly

    </div>
    <div id="optionInterest" class="options" style="display:none;">
        <input type="text" placeholder="Label" id="interestInputLabel">
        <input type="text" placeholder="Enter your Base Interest Income" id="interestInput">
        <input type="text" placeholder="Enter your Interest Rate" id="interestRateInput">
        <button id="submitInterest" class="btnIncome">Submit</button>
        
    
    </div>

<script src="dbFunctions.js"></script>
<script src="addIncome.js"></script>
</body>
</html>
Below are the addExpenses. js and addExpenses. html files respectively.
const dropdownExpenses = document.getElementById("dropdownExpenses");
const optionForms = document.querySelectorAll(".options");
//submit btns form
const submitMonthly = document.getElementById("submitMonthly");
const submitOneTime = document.getElementById("submitOneTime");
const submitMortgage = document.getElementById("submitMortgage");

//oneTimeInput
const oneTimeInputLabel = document.getElementById("oneTimeInputLabel");
const oneTimeInput = document.getElementById("oneTimeInput");
const radiosOneTime = document.getElementsByName("radioOneTime");
//monthlyInput
const monthlyInputLabel = document.getElementById("monthlyInputLabel");
const monthlyInput = document.getElementById("monthlyInput");
const radiosMonthly = document.getElementsByName("radioMonthly");
//mortgageInput
const mortgageInputLabel = document.getElementById("mortgageInputLabel");
const mortgageBasePayInput = document.getElementById("mortgageBasePayInput");
const mortgageInterestRateInput = document.getElementById("mortgageInterestRateInput");




//ultimately displays the selected item of the dropdown
dropdownExpenses.addEventListener("change", function (){
    const selectedOption = this.value;
    const showForm = document.getElementById(selectedOption);

    //makes each form invisible
    optionForms.forEach(form => {
        form.style.display = 'none';
    });
    //shows the form selected
    showForm.style.display = "block";
});
//ultimately adds data in input field to db, and updates total money
submitOneTime.addEventListener("click", function(){
    let oneTimeInputValue = parseFloat(oneTimeInput.value);
    if(isNaN(oneTimeInputValue)){
        alert("Please Enter A Number");
    }
    else{



        for (var i=0, length=radiosOneTime.length; i < length; i++){
            if(radiosOneTime[i].checked){
                var selected = radiosOneTime[i];
                break;
            }
        }


        //defines expenseName and expenseAmount to be put into addExpense
        var expenseName = oneTimeInputLabel.value;
        var expenseAmount = oneTimeInputValue;
        var expenseImportance = selected.value;
        

        //adds the name and amount into the db
        addExpense(expenseName, expenseAmount, "oneTime", undefined, expenseImportance);

        getDataByName("totalMoney", "total", function(data){
            if (data && data[0]){
                var currentTotal = data[0].total;
                var newTotal = currentTotal - oneTimeInputValue;
                updateTotalMoney(newTotal);
            } else{
                console.log("Error retreiving total Money");
            }
        });


        
}});
//ultimately adds data in input field to db
submitMonthly.addEventListener("click", function(){
    let monthlyInputValue = parseFloat(monthlyInput.value);
    if(isNaN(monthlyInputValue)){
        alert("Please enter a Number");
    }
    else{

        for (var i=0, length=radiosMonthly.length; i < length; i++){
            if(radiosMonthly[i].checked){
                var selected = radiosMonthly[i];
                break;
            }
        }

        var expenseName = monthlyInputLabel.value;
        var expenseAmount = monthlyInputValue;
        var expenseImportance = selected.value;

        addExpense(expenseName, expenseAmount, "monthly", undefined, expenseImportance);
    }
});

submitMortgage.addEventListener("click", function(){
    let mortgageBasePayInputValue = parseFloat(mortgageBasePayInput.value);
    let mortgageInterestRateInputValue = parseFloat(mortgageInterestRateInput.value);

    if(isNaN(mortgageBasePayInputValue) || isNaN(mortgageInterestRateInputValue)){
        alert("Please enter numbers for both inputs");

    }
    else{
        var expenseName = mortgageInputLabel.value;
        var expenseAmount = mortgageBasePayInputValue;
        var expenseInterest = mortgageInterestRateInputValue;

        addExpense(expenseName, expenseAmount, "mortgage", expenseInterest, undefined);

    }
});
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href = "addExpenses.css">
    <title>Document</title>
</head>
<body>
    <a href="financetracker.html">
        <p>Go Back</p>
    </a>
    <select id="dropdownExpenses">
        <option value="default">--</option>
        <option value="optionMonthly">
            Monthly Expense
        </option>
        <option value = "optionOneTime">
            One-Time Expense
        </option>
        <option value = "optionMortgage">
            Mortgage Expense
        </option>

    </select>

    <div id="default" style="display:none;" class="options"> </div>
    <div id="optionMonthly" style="display:none;" class="options">
        <input type="text" placeholder="Label" id="monthlyInputLabel">
        <input type="text" placeholder="Select A Monthly Expense Amount" id="monthlyInput">
        <button id="submitMonthly" class="btnExpenses">Submit</button>
        <input type="radio" name="radioMonthly" id="Luxury">Luxury
        <input type="radio" name="radioMonthly" id="Necessity">Necessity
        <input type="radio" name="radioMonthly" id="Favorable">Favorable
    </div>
    <div id="optionOneTime" style = "display:none;" class="options">
        <input type="text" placeholder="Label" id="oneTimeInputLabel">
        <input type="text" placeholder="Select a One-Time Expense" id="oneTimeInput">
        <button id="submitOneTime" class="btnExpenses">Submit</button>
        <input type="radio" name="radioOneTime" id="Luxury">Luxury
        <input type="radio" name="radioOneTime" id="Necessity">Necessity
        <input type="radio" name="radioOneTime" id="Favorable">Favorable
    </div>
    <div id="optionMortgage" style="display:none;" class="options">
        <input type="text" placeholder="Label" id="mortgageInputLabel">
        <input type="text" placeholder="Select your base monthly Mortgage Expense" id="mortgageBasePayInput">
        <input type="text" placeholder="Select your monthly interest rate" id="mortgageInterestRateInput">
        <button id="submitMortgage" class="btnExpenses">Submit</button>
        
    </div>
    <script src="dbFunctions.js"></script>
    <script src="addExpenses.js"></script>
</body>
</html>

below is my financetracker. js,. css, and . html

//input daily expenses, incldues consistent expenses as well as one time purchases
//include monthly expenses as well as any overarching expenses
//categorize  expenses: necessities, luxuries, one time expenses etc etc
//include wages, put in hours of work and output total profit
//then, visualize the data with various charts and tracking
//finally, for now suggest ways to cut spending


//want to calculate Income and Expenses on the daily, except for instant payments/debts.
//make choice btw implementing flat monthly rates on graph with instant or over time.
//prob over time since it would fit better on this big top max of budget/ income


//manually set totalMoney (usually to 0), then log that value in the db



document.addEventListener("DOMContentLoaded", function(){
    var totalMoney = 10000000;
    checkAndInitializeTotalMoney(totalMoney);
    //puts commas in totalMoney as well as updates text box
    function displayTotalMoney(total){
        console.log("Display Total Money is being called");
        var totalMoneyS = total.toString(); 
        for (let i = totalMoneyS.length - 3; i > 0; i-=3){
            totalMoneyS = totalMoneyS.slice(0, i) + ',' + totalMoneyS.slice(i);
        }
        
        document.getElementById("moneyAmount").textContent = totalMoneyS;
    }
    //takes the value of total in totalMoney and runs displayTotalMoney there
    function assignMoneyUse(data){
        //checks if data is not empty and that it has at least one element
        if(data && data[0]){
            displayTotalMoney(data[0].total);
        }else{
            console.log("no data found for total in totalMoney");
        }
    }



   //gets db data for totalMoney
    getDataByName("totalMoney", "total", assignMoneyUse);
    


});
.viewButtons{
    width: 350px;
    height: 200px;
    font-size: 50px;
    font-family: 'Times New Roman', Times, serif;
    border-radius: 10px;
}


.balanceBottomLine{
    position: relative;
    top: 200px;
    left: 100px;
    width: 1500px;
    height: 5px;
    background-color: black;
}

#addExpenses{
    position: absolute;
    top:100px;
    left:100px;
    


}

#addIncome{
    position: absolute;
    top: 100px;
    left: 500px;
   
}

#statistics{
    position: absolute;
    top: 100px;
    left: 900px;
}

.dataVisBox{
    position: relative;
    top: 600px;
    left:125px;
    width:1500px;
    height:1000px;
    border:5px solid black;
    
}

.moneyHave{
    position: absolute;
    top: -110px;
    font-size: 100px;
    font-family: Arial, Helvetica, sans-serif;
}

.moneyHave p{
    display: inline;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="financetracker.css">
</head>
<body>
    <div class="balanceBottomLine"> 
    <a href="addExpenses.html">
    <button id="addExpenses" class="viewButtons">Add Expenses </button>
    </a>
    <a href = "addIncome.html">
    <button id="addIncome" class="viewButtons">Add Income</button>
    </a>
    <a href = "checkStatistics.html">
    <button id="statistics" class="viewButtons">Check Statistics</button>
    </a>
    <div class="moneyHave">
        <p class="currencySign">$</p> <p class="moneyAmount" id="moneyAmount">000,000,000,000</p>
        
        </div>
</div>
<div class="dataVisBox">


</div>
    <script src="dbFunctions.js"></script>
    <script src="financetracker.js"></script>
</body>
</html>
  • Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Konrad Aug 24 '23 at 06:30

1 Answers1

1

The reason for the error here was that the db variable in the dbFunctions.js file was showing as undifined in the checkAndInitializeTotalMoney() method.

Solution 1

Solution 1: You can solve this problem by using the Promise and await constructs so that the db is accessed first and then the checkAndInitializeTotalMoney() method. This is the first solution.

In that: dbFunctions.js AND finanstracker.html

let db;
let request = indexedDB.open("financeManager", 1);


function openDb() {
    return new Promise((resolve, reject) => {
        request.onupgradeneeded = function(event) {
            db = event.target.result;
            db.createObjectStore("expenses", { keyPath: 'id', autoIncrement: true });
            db.createObjectStore("incomes", { keyPath: 'id', autoIncrement: true });
            db.createObjectStore("totalMoney", { keyPath: 'id', autoIncrement: true });
            if (!db.objectStoreNames.contains("totalMoney")) {
                
            }
        };

        request.onsuccess = function(event) {
            db = event.target.result;
            console.log("is db ok: " + db);
            resolve(db); //if db open success then accept and return
        };

        request.onerror = function(event) {
            console.log('error', event.target.errorCode);
            reject(event.target.errorCode); 
        };
    });
}

async function init(totalMoney) {
    try {
        await openDb();
        checkAndInitializeTotalMoney(totalMoney);
    } catch (error) {
        console.error("When db try to open error: ", error);
    }
}


function initializeTotalMoney(total){
    var transaction = db.transaction(['totalMoney'], 'readwrite');
    var objectStore = transaction.objectStore('totalMoney');

    var totalMoney = {
        'total': total
    };
    var request = objectStore.add(totalMoney);

    request.onsuccess = function(event){
        console.log("Successfull");
    }

    request.onerror = function(event){
        console.log("error adding total:" ,event.target.error);
    }
}


function checkAndInitializeTotalMoney(InitialValue) {

  console.log("db: " + db)

  var transaction = db.transaction(['totalMoney'], 'readonly');
  var objectStore = transaction.objectStore('totalMoney');

  var getRequest = objectStore.get(1);

  getRequest.onsuccess = function(e){
      if (!e.target.result){
          initializeTotalMoney(InitialValue);
      } else{
          console.log("totalMoney already initialized: ", e.target.result);
      }
  };
  getRequest.onerror = function(e){
      console.log("Error checking tot money: ", e.target.error);
  };


}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="financetracker.css">
</head>
<body>
    <div class="balanceBottomLine"> 
    <a href="addExpenses.html">
    <button id="addExpenses" class="viewButtons">Add Expenses </button>
    </a>
    <a href = "addIncome.html">
    <button id="addIncome" class="viewButtons">Add Income</button>
    </a>
    <a href = "checkStatistics.html">
    <button id="statistics" class="viewButtons">Check Statistics</button>
    </a>
    <div class="moneyHave">
        <p class="currencySign">$</p> <p class="moneyAmount" id="moneyAmount">000,000,000,000</p>
        
        </div>
</div>
<div class="dataVisBox">


</div>
    <script src="dbFunctions.js"></script>
    <script src="financetracker.js"></script>
</body>
</html>

AND CALL THE init() METHOD IN financetracker.js LIKE THIS:

document.addEventListener("DOMContentLoaded", function(){
    var totalMoney = 10000000;
    init(totalMoney);

});

Solution 2

Solution 2: If you want a less complex structure; You may want to open the db before each db operation and do your operations.

dbFunctions.js

    let db;
    let request = indexedDB.open("financeManager", 1);

    request.onupgradeneeded = function(event){
        
        db = event.target.result;
        db.createObjectStore("expenses", { keyPath:'id', autoIncrement: true});
        db.createObjectStore("incomes", {keyPath: 'id', autoIncrement: true});
        db.createObjectStore("totalMoney", {keyPath: 'id', autoIncrement: true});

        
        if(!db.objectStoreNames.contains("totalMoney")){

        }
        
    };



    request.onsuccess = function(event){
        db = event.target.result;
        console.log("is db ok: " + db);
    
    };

    request.onerror = function(event){
        console.log('error', event.target.errorCode);
    };

    //should only be used once, adds totalMoney as a db 
    function initializeTotalMoney(total){
        var transaction = db.transaction(['totalMoney'], 'readwrite');
        var objectStore = transaction.objectStore('totalMoney');

        var totalMoney = {
            'total': total
        };
        var request = objectStore.add(totalMoney);

        request.onsuccess = function(event){
            console.log("Successfull");
        }

        request.onerror = function(event){
            console.log("error adding total:" ,event.target.error);
        }
    }

    function checkAndInitializeTotalMoney(db, InitialValue) {
        //OPEN HERE AGAIN
        const request = window.indexedDB.open("financeManager");
        request.onsuccess = (event) => {
        const db = event.target.result;

    console.log("db: " + db)

    var transaction = db.transaction(['totalMoney'], 'readonly');
    var objectStore = transaction.objectStore('totalMoney');

    var getRequest = objectStore.get(1);

    getRequest.onsuccess = function(e){
        if (!e.target.result){
            initializeTotalMoney(InitialValue);
        } else{
            console.log("totalMoney already initialized: ", e.target.result);
        }
    };
    getRequest.onerror = function(e){
        console.log("Error checking tot money: ", e.target.error);
    };

    }
    }

AND CALL THE init() METHOD IN financetracker.js LIKE THIS:

document.addEventListener("DOMContentLoaded", function(){
    var totalMoney = 10000000;
    checkAndInitializeTotalMoney(totalMoney);
});

After trying either of these two solutions, the console output: console output after solutions

ozgurbyk
  • 75
  • 7