我是索引数据库的新手,所以这可能是一个简单的修复,但我似乎无法在我的代码中找到任何修复。我正在使用实时服务器来显示它,我面临的问题是它应该在 html 中显示总金额,但它在控制台中给了我一个错误:。谢谢您的考虑
下面是我的 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);
};
}
下面是addIncome。 js 和 addIncome.js 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>
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>
下面是我的财务追踪器。 js,. CSS 和 . 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>
此处错误的原因是 dbFunctions.js 文件中的 db 变量在 checkAndInitializeTotalMoney() 方法中显示为未定义。
解决方案1
解决方案1:您可以通过使用Promise和await结构来解决这个问题,这样首先访问db,然后访问checkAndInitializeTotalMoney()方法。这是第一个解决方案。
其中: dbFunctions.js 和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>
并像这样调用financetracker.js中的init()方法:
document.addEventListener("DOMContentLoaded", function(){
var totalMoney = 10000000;
init(totalMoney);
});
解决方案2
解决方案2:如果您想要不太复杂的结构;您可能希望在每次数据库操作之前打开数据库并执行您的操作。
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);
};
}
}
并像这样调用financetracker.js中的init()方法:
document.addEventListener("DOMContentLoaded", function(){
var totalMoney = 10000000;
checkAndInitializeTotalMoney(totalMoney);
});