I've made a budgeting app that has expenses and Income tabs. Every time you add an expense or income, the app pushes the information inside of an array of objects and dynamically renders an <li> component and places it inside of a <ul>. I'm having trouble with the edit and delete features. Each individual <li> comes with a delete and edit button. The <li>, delete button, and edit button all have the same id of Date.now(). Date.now() is used because it produces a number based on milliseconds and won't produce the same id twice unless someone types an expense or income twice within one millisecond I want to click on the delete button inside of the <li> and have my app remove that individual object from my entry_list[] array and also remove the <li> from the DOM.
'use strict'
const balanceElement = document.querySelector(".balance .value");
const totalIncome = document.querySelector(".income-total");
const totalOutcome = document.querySelector(".outcome-total");
const incomeElement = document.querySelector(".income-tab");
const expense = document.querySelector(".expense-tab");
const all = document.querySelector(".all-tab");
const incomeList = document.querySelector(".income-tab .list");
const expenseList = document.querySelector(".expense-tab .list");
const allList = document.querySelector(".all-tab .list");
const expensesButton = document.querySelector(".tab1");
const incomeButton = document.querySelector(".tab2");
const allButton = document.querySelector(".tab3");
const addExpense = document.querySelector(".add-expense")
const expenseTitle = document.querySelector(".expense-title-input")
const expenseAmount = document.querySelector(".expense-amount-input")
const addIncome = document.querySelector(".add-income")
const incomeTitle = document.querySelector(".income-title-input")
const incomeAmount = document.querySelector(".income-amount-input")
const list = document.querySelector('.list')
//SWITCHING BETWEEN TABS
expensesButton.addEventListener('click', () => {
expense.classList.remove('hidden');
incomeElement.classList.add('hidden');
expensesButton.classList.add('clicked');
incomeButton.classList.remove('clicked');
})
incomeButton.addEventListener('click', () => {
incomeElement.classList.remove('hidden');
expense.classList.add('hidden');
expensesButton.classList.remove('clicked');
incomeButton.classList.add('clicked');
})
incomeList.addEventListener('click', deleteOrEdit)
expenseList.addEventListener('click', deleteOrEdit)
let entry_list = []
addExpense.addEventListener('click', () =>{
if(expenseTitle.value == '' || expenseAmount.value == ''){
return;
}
let expense = {
type: 'expense',
title: expenseTitle.value,
amount: expenseAmount.value,
id: Date.now()
}
entry_list.push(expense)
clearExpense()
changeLists()
})
addIncome.addEventListener('click', () =>{
if(incomeTitle.value == '' || incomeAmount.value == ''){
return;
}
let income = {
type: 'income',
title: incomeTitle.value,
amount: incomeAmount.value,
id: Date.now()
}
entry_list.push(income)
clearIncome()
changeLists()
})
const clearExpense = () =>{
expenseTitle.value = '';
expenseAmount.value = '';
}
const clearIncome = () =>{
incomeTitle.value = ''
incomeAmount.value = ''
}
const changeLists = () =>{
expenseList.innerHTML = ''
incomeList.innerHTML = ''
entry_list.map((entry) =>{
if(entry.type == 'expense'){
return expenseList.innerHTML += `<li id = "${entry.id}" class= "${entry.type}">
<div class = "entry">${entry.title}: $${entry.amount}</div>
<div class="icon-container">
<div class = "edit" id="${entry.id}"></div>
<div class ="delete" id="${entry.id}"></div>
</div>
</li>`
}
else if(entry.type == 'income'){
return incomeList.innerHTML += `<li id = "${entry.id}" class= "${entry.type}">
<div class = "entry">${entry.title}: $${entry.amount}</div>
<div class="icon-container">
<div class = "edit" id="${entry.id}"></div>
<div class ="delete" id="${entry.id}"></div>
</div>
</li>`
}
})
addIncomes()
}
const addIncomes = () =>{
let sum = 0;
let income = 0;
let outcome = 0;
balanceElement.innerHTML = 0
totalIncome.innerHTML = 0
totalOutcome.innerHTML = 0
entry_list.forEach(list =>{
if(list.type == 'expense'){
sum -= list.amount
outcome -= list.amount
}else if(list.type == 'income'){
sum += Number(list.amount)
income += Number(list.amount)
}
balanceElement.innerHTML = '$' + sum
totalIncome.innerHTML = '$' + income
totalOutcome.innerHTML = '$' + outcome
})
}
// // DETERMINE IF BUTTON IS EDIT OR DELETE
function deleteOrEdit(e){
const targetButton = e.target;
const entry = targetButton.parentNode.parentNode;
if(targetButton.classList == ('delete')){
deleteEntry(entry)
}else if(targetButton.classList == ('edit')){
editEntry(entry);
}
}
// //DELETE FUNCTION
const deleteEntry = (entry) =>{
console.log(entry.id)
entry_list.splice(entry.id, 1)
// entry.innerHTML = ''
console.log(entry.id)
addIncomes()
}
// EDIT FUNCTION
const editEntry = (entry) =>{
let Entry = entry_list[entry.id]
if(entry.type == "income"){
incomeAmount.value = Entry.amount;
incomeTitle.value = Entry.title;
}else if(entry.type == "expense"){
expenseAmount.value = Entry.amount;
expenseTitle.value = Entry.title;
}
deleteEntry(entry);
}
#import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght#400;700&family=Raleway:wght#400;700&display=swap');
*{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Open Sans', sans-serif;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.budget-container{
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100%;
background-color: #4F98CA;
}
.balance-container{
width: 360px;
height: 470px;
background-color: #50D890;
border-radius: 30px;
margin-right: 100px;
}
.app-title{
color: white;
margin-top: 1rem;
margin-left: 1rem;
}
.month{
color: white;
margin-top: 1rem;
text-align: center;
}
.budget-header{
display: flex;
flex-direction:column;
justify-content: center;
}
.balance{
margin-top: 1rem;
margin-left: 1rem;
}
.title{
color: white;
font-size: 1.25rem;
opacity: .75;
}
.value{
font-size: 1.75rem;
color: white;
font-weight: bold;
margin-left: 1rem;
}
.account{
margin-top: 2.5rem;
margin: 2.5rem 1.5rem 2.5rem 1.5rem;
display: flex;
justify-content: space-between
}
.income-total{
color: white;
text-align: center;
font-size: 1.5rem;
}
.outcome-total{
color: #4F98CA;
text-align: center;
font-size: 1.5rem;
}
/* DASHBOARD */
.budget-dashboard{
display: block;
width: 360px;
height: 470px;
position: relative;
border-radius: 30px;
background-color: white;
}
.dash-title{
margin-top: 2rem;
margin-left: 1rem;
font-size: 1.5rem;
}
.toggle{
margin: 1rem;
display: flex;
cursor: pointer;
}
.toggle .tab2, .tab3{
margin-left: 1rem;
cursor: pointer;
}
.clicked{
font-weight: bold !important;
}
.hidden{
display: none !important;
}
/* EXPENSES TAB */
.expense-tab{
display: flex;
justify-content: center;
}
.expense-input-container{
position: absolute;
top: 400px;
border-top: solid 1px gray;
width: 100%;
}
.expense-amount-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.expense-title-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.add-expense{
color: none;
background-color: none;
border: none;
outline: none;
color: inherit;
}
/* INCOME TAB */
.income-tab{
display: flex;
justify-content: center;
}
.income-input-container{
position: absolute;
top: 400px;
border-top: solid 1px gray;
width: 100%;
}
.input{
display: flex;
justify-content: space-between;
align-items: center;
margin: 1rem;
}
.income-amount-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.income-title-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.add-income{
color: none;
background-color: none;
border: none;
outline: none;
}
.plus-img{
width: 40px;
}
/* li */
ul{
width: 360px;
height: 255px;
list-style: none;
margin-top:20px;
overflow-x: auto;
}
/* BUTTON ICONS */
.edit{
background-image: url('media/Icons/icons8-edit-48.png');
background-size: contain;
width: 25px;
height: 25px;
background-repeat: no-repeat;
margin-right: 10px;
}
.delete{
background-image: url('media/Icons/icons8-trash-can-48 (2).png');
background-size: contain;
width:25px;
height: 25px;
background-repeat: no-repeat;
}
.income{
width:250px;
height: auto;
padding-left: 20px;
margin-bottom: 10px;;
word-wrap: break-word;
color: black
}
.expense{
width:250px;
height: auto;
padding-left: 20px;
margin-bottom: 10px;;
word-wrap: break-word;
font-family: 'Gilroy Bold';
color: #4F98CA;
}
li{
display: flex;
justify-content: space-between;
width: 100% !important;
padding-right: 20px;
}
.icon-container{
display: flex;
}
#media (max-width:900px){
.budget-container{
display: inline-block;
position: relative
}
.balance-container{
position: absolute;
top: 10%;
left: 25%;
}
.budget-dashboard{
position: absolute;
left: 25%;
top: 40%;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Budgetrr</title>
</head>
<body>
<main class="budget-container">
<section class="balance-container">
<div class="app-title">
<p>Budgetrr</p>
</div>
<h1 class="month">OCTOBER</h1>
<section class="budget-header">
<div class="balance">
<div class="title">
Balance
</div>
<div class="value">
<small>$</small>0
</div>
</div>
<div class="account">
<div class="budget-income">
<div class="title">
Income
</div>
<div class="income-total">
<small>$</small>0
</div>
</div>
<div class="chart"></div>
<div class="budgetoutcome">
<div class="title">
Expenses
</div>
<div class="outcome-total">
<small>$</small>0
</div>
</div>
</div>
</section>
</section>
<section class="budget-dashboard">
<div class="dash-title">Dashboard</div>
<div class="toggle">
<div class="tab1 clicked">Expenses</div>
<div class="tab2">Income</div>
<!-- <div class="tab3 clicked">All</div> -->
</div>
<div class="income-tab hidden">
<ul class="list"></ul>
<div class="income-input-container">
<form class="input">
<input type="text" class="income-title-input" name="title" placeholder="Title">
<input type="number" class="income-amount-input" name="amount" placeholder="$0">
<button type = "button" class="add-income"><img class= "plus-img"src="media/Icons/icons8-add-new-48.png" alt=""></button>
</form>
</div>
</div>
<div class = "expense-tab">
<ul class="list"></ul>
<div class="expense-input-container">
<div class="input">
<input type="text" class="expense-title-input" name="title" placeholder="Title">
<input type="number" class="expense-amount-input" name="amount" placeholder="$0">
<button type="button" class="add-expense"><img class= "plus-img" src="media/Icons/icons8-add-new-48.png" alt=""></button>
</div>
</div>
</div>
</section>
</main>
<script src="JavaScript/budget.js"></script>
</body>
</html>
I've tried to use .splice() but I can't seem to get it to work.
Your entry is an object. And entry has an id property with Date type.
Your delete function calls this:
entry_list.splice(entry.id, 1)
Javascript splice function
function takes number as argument(s).
You should find the id of element you want to delete and get its index. After that you can delete the element with splice method.
Here is how to delete:
// Find the index of object at the given list
const index = entry_list.findIndex(x => x.id === entry.id);
// Starting from index of element to delete, remove 1 element.
entry_list.splice(index, 1);
Related
I have not been able to figure out why my calculator is returning undefined. I have it set up to return the result but I can't figure out why it doesn't return the actual calculation. I have console.log() my numbers and operator and they will show up but it never calculates. On the screen it returns undefined. Thanks so much to anyone that helps!
JS Code
const screen =document.querySelector('.screen')
const clear =document.querySelector('.clear')
const numberButtons =document.querySelectorAll('.numbers')
const operators =document.querySelectorAll('.operators')
const equal =document.querySelector('.equal')
let previousValue ='';
let currentValue ='';
let result = '';
//code for numbers to show values on screen
numberButtons.forEach(function(numberButton){
numberButton.addEventListener("click",function(){
screen.textContent+=numberButton.value;
currentValue=parseInt(screen.innerText);
})
})
// code for +-/*
operators.forEach(function(operators){
operators.addEventListener("click",function(){
screen.textContent+=operators.value;
currentValue=(screen.innerText);
})
})
//function for math equations
function calculate(operators,previousValue,currentValue) {
console.log(previousValue);
console.log(operators);
console.log(currentValue);
previousValue = parseInt(previousValue)
currentValue = parseInt(currentValue)
if (operators == '+') {
result = previousValue += currentValue
} else if (operators == '-') {
result = previousValue -= currentValue
} else if (operators == '*') {
result = previousValue *= currentValue
} else {
result = previousValue /= currentValue
}
screen.textContent += calculate.value
currentValue = (screen.innerText)
return result ;
}
//function to compute once equal is clicked
equal.addEventListener("click", button => {
screen.textContent+=equal.value;
currentValue=(screen.innerText);
if (previousValue != "" && currentValue != "" && operators != ""){
return result;
}
calculate(operators,previousValue,currentValue)
})
clear.addEventListener('click',() => location.reload());
CSS
html, body {
height: 100%;
width: 100%;
}
div.calc{
font-family: 'Courier New', monospace;
color: #FB6F92;
font-size: 40px ;
font-weight: bolder;
margin-left: 625px;
margin-top: 25px;
}
div.container{
background:#e7e7e7;
width: 500px;
height: 555px;
border-radius: 10px;
border: 5px solid #FB6F92;
margin-left: 500px;
margin-top: 25px;
box-shadow: 10px 10px 10px;
}
div.screen{
border: 5px solid #FB6F92;
color: black;
background: #f8f8ff;
width: 445px;
height: 100px;
border-radius: 10px;
margin-left: 20px;
font-size: 30px;
text-align: right;
font-weight: bold;
font-family: 'Courier New', monospace;
}
button.clear{
width: 450px;
height: 50px;
background:#FFCCF9;
color:black;
border-radius: 5px;
margin-left: 22px;
margin-top: 6px;
}
button.clear:hover{
background:#Ff9cee;
}
button.numbers{
width: 75px;
height: 75px;
background: pink;
color:white;
border-radius: 5px;
margin-left: 35px;
margin-top: 15px;
font-weight: bold;
font-size: 20px;
}
button.numbers:hover{
background: #FB6F92;
}
button.operators{
width: 75px;
height: 75px;
background: #A4E7DF;
color:black;
border-radius: 5px;
margin-left: 35px;
margin-top: 15px;
font-weight: bold;
font-size: 20px;
}
button.operators:hover{
background: #3bc6b6;
#64d4c7
}
button.equal{
width: 190px;
height: 75px;
background: #D1B2EA;
color:black;
border-radius: 5px;
margin-left: 35px;
margin-top: 15px;
font-weight: bold;
font-size: 20px;
}
button.equal:hover{
background:#b07cda;
}
footer{
font-family: 'Courier New', monospace;
color: #FB6F92;
font-size: 36px ;
font-weight: bolder;
margin-left: 510px;
margin-top: 20px;
}
html, body {
height: 100%;
width: 100%;
}
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Calculator TOP Project</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body style = 'background-color :#a0ddfb;'>
<div class = "calc"> Calculator</div>
<div class = "container">
<br>
<div class="screen" value = "screen"></div>
<button class = "clear" onclick="clear();" >Clear</button>
<br>
<button class = 'numbers' value="7" > 7</button>
<button class = 'numbers' value="8">8</button>
<button class = 'numbers' value="9">9</button>
<button class = 'operators' value="÷"> ÷</button>
<br>
<button class = 'numbers' value="4">4</button>
<button class = 'numbers'value="5">5</button>
<button class = 'numbers' value="6">6</button>
<button class = 'operators' value="*" > ×</button>
<br>
<button class = 'numbers' value="1" >1</button>
<button class = 'numbers' value="2" >2</button>
<button class = 'numbers' value="3" >3</button>
<button class = 'operators' value = "-" >-</button>
<br>
<!-- <button class = 'numbers' value=".">.</button> -->
<button class = 'numbers' value ="0" >0</button>
<button class = 'equal' value="=" >=</button>
<button class = 'operators' value = "+" >+</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
Looks like you have a bad line.
Observe your js file on this line:
screen.textContent += calculate.value
calculate is the name of your function. It has no attribute value.
You probably want to replace calculate.value to result like so:
screen.textContent += result
Also you have some errors above that:
previousValue = parseInt(previousValue)
currentValue = parseInt(currentValue)
parseInt of an empty String will give you a a value of NaN (Not a number).
You also have a handful of logic bugs that you have to fix.
The undefined bug is just 1 bug that you have to fix.
I am implementing a simulation of a Dutch- and an English-auction in otree.
For the interface, I am using a progress bar for the price that the supplier gets.
In the English-auction the price increases every half second and in the Dutch-auction the price decreases every half second.
Now I want to add a vertical line for the costs of the supplier, which changes every round.
How can i add a vertical line to the progress bar?
<style>
#myProgress {
width: 100%;
background-color: #ddd;
}
#myCosts {
width: 100%;
background-color: #ddd;
}
#myBar {
width: 100%;
height: 30px;
background-color: #40bf80;
text-align: center;
line-height: 30px;
color: white;
}
#costLine{
width: 0%;
height: 30px;
background-color: #FF0000;
text-align: center;
line-height: 30px;
color: white;
}
.bg-info{
background-color: #ddd;
}
</style>
Your costs for this round are:
<div id="myCosts">
<div id="costLine">{{player.cost}}</div>
</div>
Current price is:
<div id="myProgress">
<div id="myBar">$200</div>
</div>
<p></p>
<p id="Message"></p>
<script>
var left_line = ({{player.cost|json}}-101);
var right_line = (200-{{player.cost|json}});
let cost = {{player.cost|json}}
let bot_stop = {{player.bot_stop|json}};
let price = {{Constants.start_value|json}};
var Auction;
var Auction2;
document.getElementById("costLine").innerHTML = "$"+cost;
document.getElementById("costLine").style.width = cost-100+'%';
function startAuction(){
document.getElementById("stop_button").disabled = false;
document.getElementById("start_button").disabled = true;
Auction = setInterval(function(){
if(price == bot_stop){
document.getElementById("Message").innerHTML = 'The other supplier has dropped out. You win with a price of ' + bot_stop;
document.getElementById("stop_button").innerHTML = 'Next Page'
stopAuction();
}
if(price != bot_stop){
price = price -1;
document.getElementById("myBar").innerHTML='$'+price;
document.getElementById("myBar").style.width = (price-100) +'%';
}
},500)
}
function stopAuction() {
document.querySelector("[name=winning_price]").value = price;
document.getElementById("stop_button").innerHTML = 'Next Page'
clearInterval(Auction);
}
</script>
<button type="button" class="otree-btn-next btn btn-primary" id="start_button" onclick="startAuction()">Start Auction</button>
<button class="otree-btn-next btn btn-primary" disabled id="stop_button" onclick="stopAuction()">Drop Out</button>
<p></p>
<p></p>
<input type="hidden" name="winning_price" />
Add a child element <div id=myBarPrice></div> to <div id="myProgress">.
Add position: relative; attribute to the #myProgress selector.
Add new style block for a new element:
#myBarPrice {
background-color: #FF0000;
width: 2px;
height: 100%;
position: absolute;
right: 100%;
top: 0;
}
Set #myBarPrice position with js:
...
document.getElementById("costLine").innerHTML = "$"+cost;
document.getElementById("costLine").style.width = cost-100+'%';
document.getElementById("myBarPrice").style.right = cost+'%'; // <=====
function startAuction(){
document.getElementById("stop_button").disabled = false;
document.getElementById("start_button").disabled = true;
...
Here is a mockup in codepen.io
CSS code:
#myProgress {
width: 100%;
background-color: #ddd;
position: relative;
}
#myCosts {
width: 100%;
background-color: #ddd;
}
#myBar {
width: 80%;
height: 30px;
background-color: #40bf80;
text-align: center;
line-height: 30px;
color: white;
}
#myBarPrice {
background-color: #FF0000;
width: 2px;
height: 100%;
position: absolute;
right: 40%;
top: 0;
}
#costLine{
width: 60%;
height: 30px;
background-color: #FF0000;
text-align: center;
line-height: 30px;
color: white;
}
.bg-info{
background-color: #ddd;
}
HTML code:
Your costs for this round are:
<div id="myCosts">
<div id="costLine">{{player.cost}}</div>
</div>
Current price is:
<div id="myProgress">
<div id="myBar">$200</div>
<div id=myBarPrice></div>
</div>
`
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Task Manager</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
<div id="main-container">
<header>
<h1>TASK MANAGER</h1>
<div id="task-value-check" class="value-check"></div>
<div id="member-value-check" class="value-check"></div>
<div id="input">
<div id="task-form">
<form onsubmit="createTask(event)">
<input class="text-input" name="task" type="text" placeholder="Name of
new task">
<input class="button" type="submit" value="ADD"/>
</form>
</div>
<div id="tasks-header" class="header">TASKS</div>
<div id="member-form">
<form onsubmit="createMember(event)">
<input class="text-input" name="teamMember" type="text"
placeholder="Name of new team member">
<input class="button" type="submit" value="ADD"/>
</form>
</div>
<div id="members-header" class="header">TEAM MEMBERS</div>
</div>
</header>
<main>
<div id="assign-value-check" class="value-check"></div>
<div id="assign-form">
<form onsubmit="assignToMember(event)">
<input class="text-input" class="input-txt" id="check-task" type="text"
placeholder="Pick task">
<input type="submit" id="assign-button" value="ASSIGN" class="button"
class="input-submit">
</form>
</div>
<div id="assignments-header" class="header">TASK ASSIGNMENTS</div>
<main>
<div id="listing">
<div id="tasks-rendering" class="rendering"></div>
<div id="members-rendering" class="rendering"></div>
<div id="assignments-rendering" class="rendering"></div>
</div>
</main>
</div>
<script src=index.js></script>
</body>
</html>
function createTask(event) {
event.preventDefault();
let task = document.querySelector("[name='task']").value;
task = task.toLowerCase();
const taskList = JSON.parse(localStorage.getItem('task')) || [];
if (task === "") {
document.getElementById("task-value-check").innerHTML = "PLEASE ENTER A TASK";
} else {
document.getElementById("task-value-check").innerHTML = "";
document.getElementById("member-value-check").innerHTML = "";
const tasks = { task};
taskList.push(tasks);
window.localStorage.setItem('task', JSON.stringify(taskList));
event.target.reset();
renderTaskList();
}
}
function createMember(event) {
event.preventDefault();
let member = document.querySelector("[name='teamMember']").value;
member = member.toLowerCase();
if (member === "") {
document.getElementById("member-value-check").innerHTML = "PLEASE ENTER A TEAM MEMBER";
} else {
document.getElementById("member-value-check").innerHTML = "";
document.getElementById("task-value-check").innerHTML = "";
const members = { member };
const memberList = JSON.parse(localStorage.getItem('member')) || [];
memberList.push(members);
window.localStorage.setItem('member', JSON.stringify(memberList));
event.target.reset();
renderMemberList();
}
}
function assignToMember(event) {
event.preventDefault();
const taskList = JSON.parse(localStorage.getItem('task')) || {};
let nameTask = document.getElementById('check-task').value;
let valueCheck = document.getElementById('assign-value-check');
if (nameTask === "") {
valueCheck.innerHTML = "PLEASE ENTER A TASK AND A TEAM MEMBER";
} else if (nameTask === "") {
valueCheck.innerHTML = "PLEASE ENTER A TASK";
} else {
valueCheck.innerHTML = "";
nameTask = nameTask.toLowerCase();
const assignMemberList = JSON.parse(localStorage.getItem('assignment')) || [];
let task;
if (nameTask != '') {
for (const a of taskList) {
if (a.task === nameTask) {
task = a.task;
}
}
if (task != undefined) {
let assignToMember = {task};
assignMemberList.push(assignToMember);
window.localStorage.setItem('assignment', JSON.stringify(assignMemberList));
} else {
valueCheck.innerHTML = "PLEASE ENTER AN EXISTING TASK AND/OR TEAM MEMBER";
}
renderUpdatedTaskList();
}
event.target.reset();
}
}
function renderTaskList() {
const taskList = JSON.parse(window.localStorage.getItem("task")) || [];
const taskListOutput = document.getElementById("tasks-rendering");
taskListOutput.innerHTML = "";
for (const a of taskList) {
let taskElement = document.createElement("div");
taskElement.innerHTML = `<div class="object-render">
<h4>${a.task.charAt(0).toUpperCase() + a.task.slice(1)}</h4>
</div>`;
taskListOutput.appendChild(taskElement);
}
}
function renderMemberList() {
const memberList = JSON.parse(window.localStorage.getItem("member")) || [];
const memberListOutput = document.getElementById("members-rendering");
memberListOutput.innerHTML = "";
for (const m of memberList) {
let memberElement = document.createElement("div");
memberElement.innerHTML = `<div class="object-render" draggable="true"
ondragstart="drag(event)">
<h4 id="drag1">${m.member.charAt(0).toUpperCase() +
m.member.slice(1)}</h4>
</div>`;
memberListOutput.appendChild(memberElement);
}
}
I am trying to drag and drop names to different tasks, but when I do the names i drop only
appears on the first created task. I want to be able to drag and drop names to the task I want. I also want them to stay there when the site is refreshed.
function renderUpdatedTaskList(){
const assignMemberList = JSON.parse(localStorage.getItem('assignment')) || [];
const assignmentListOutput = document.getElementById('assignments-rendering');
assignmentListOutput.innerHTML = "";
for (const a of assignMemberList) {
let assignmentElement = document.createElement("div");
assignmentElement.innerHTML = `<div id="assignment-object-render" class="object-render-
assignments"
class="containers" ondragover="allowdrop(event)">
<h1>${a.task.charAt(0).toUpperCase() + a.task.slice(1)}</h1>
<br>
<p>medlemmer</p>
<div class="membersDiv" ondragover="allowdrop(event)" ondrop="drop(event)">
</div>
</div>`;
assignmentListOutput.appendChild(assignmentElement);
}
renderMemberNamesOnTask();
}
function allowdrop(ev) {
ev.preventDefault();
}
function drag(ev) {
let memberInfo = ev.target.innerText;
ev.dataTransfer.setData("text/plain", memberInfo);
}
function drop(ev) {
ev.preventDefault();
const taskAndMember = JSON.parse(localStorage.getItem("taskAndMember")) || [];
let memberInfo = ev.dataTransfer.getData("text/plain");
task = ev.target.parentElement.querySelector("h1").innerText;
ev.target.append(memberInfo);
memberAndTask = {task, memberInfo};
taskAndMember.push(memberAndTask);
window.localStorage.setItem("taskAndMember", JSON.stringify(taskAndMember));
renderUpdatedTaskList();
}
function renderMemberNamesOnTask(){
const taskAndMember = JSON.parse(localStorage.getItem("taskAndMember")) || [];
let membersDiv = document.querySelectorAll(".membersDiv");
membersDiv.innerHTML = "";
for(const m of taskAndMember){
let htmlTxt = document.createElement("div");
htmlTxt.innerHTML = `${m.memberInfo}`;
Every name i drag on to a task will only appear on the first created task. I am pretty sure the problem lies somewhere here.
membersDiv.appendChild(htmlTxt);
}
}
`
`
body{
margin: 0;
padding: 0;
font-family: 'Oswald', sans-serif;
}
#main-container{
position: relative;
background-color: gainsboro;
margin: 0 auto;
width: 800px;
height: 1000px;
border-bottom: 30px solid floralwhite;
}
header{
z-index: 2;
position: absolute;
width: 800px;
height: 100px;
background-color: floralwhite;
text-align: center;
}
.text-input{
font-size: 15px;
border: 1px solid white;
height: 17px;
width: 250px;
}
.button{
font-size: 14px;
border: 1px solid white;
color: grey;
height: 20px;
width: 50px;
}
#task-form{
position: absolute;
left: 40px;
margin-top: 15px;
top: 110px;
}
#member-form{
position: absolute;
right: 40px;
margin-top: 15px;
top: 110px;
}
.value-check{
position: absolute;
z-index: 3;
top: 110px;
font-size: 12px;
color: red;
}
#task-value-check{
left: 40px;
}
#member-value-check{
right: 210px;
}
#assign-value-check{
top: 561px;
left: 135px;
}
.header{
position: absolute;
z-index: 2;
top: 170px;
background-color: antiquewhite;
color: grey;
border-bottom: 1px solid white;
height: 20px;
width: 370px;
font-size: 15px;
padding: 10px;
}
#tasks-header{
left: 0px;
}
#members-header{
right: 0px;
}
#assignments-header{
top: 620px;
width: 780px;
text-align: center;
}
#assign-form{
position: absolute;
left: 220px;
top: 578px;
}
#check-task{
position: absolute;
left: -85px;
}
#check-member{
position: absolute;
right: -445px;
}
#assign-button{
position: absolute;
width: 80px;
left: 450px;
}
#plus-symbol{
position: absolute;
color: white;
top: -28px;
left: 175.5px;
}
#assignment-object-render{
background-color: floralwhite;
padding: 20px;
padding-bottom: 50px;
font-size: 10px;
text-align: center;
}
.object-render{
background-color: floralwhite;
padding: 20px;
font-size: 10px;
text-align: center;
width: 62px;
word-wrap: break-word;
overflow-y: auto;
height: 55px;
}
.object-render-assignments{
background-color: floralwhite;
padding: 20px;
font-size: 10px;
text-align: center;
}
#tasks-rendering{
top: 210px;
}
#members-rendering{
top: 210px;
right: 0px;
}
#assignments-rendering{
bottom: 20px;
width: 760px;
height: 280px;
}
.rendering{
position: absolute;
background-color: antiquewhite;
font-family: sans-serif;
padding: 20px;
width: 350px;
height: 300px;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
grid-row-gap: 20px;
grid-column-gap: 20px;
overflow: auto;
}
.membersDiv{
height: 70px;
width: 200px;
background-color: lightgray;
overflow-y: scroll;
}
This is the css code.
`
So I taught myself coding a few years ago, and got it just enough to put together a few tools for work. I recently had to migrate my site out of CodePen and onto an actual web server. Now I'm having an issue where part of my javascript is executing properly (a portion that empties all other input fields when a user enters an input field using JQuery), but the button that calculates an answer will not work. I believe the .click is not picking it up. Either way I'm not getting error messages, the button just does nothing when I press it.
When I put the code in a snippet to share with you guys, it works (just like it did in CodePen), but the exact same code on my web host does not work. I'm really at a loss here and any help would be greatly appreciated. I feel like I'm missing some small line of code that's supposed to be included in all web files.
$(document).ready(function() {
//Clear out input fields when not selected
$("#sg").focusin(function() {
$("#density").val("");
});
$("#density").focusin(function() {
$("#sg").val("");
});
$("#pounds").focusin(function() {
$("#grams").val("");
$("#percentage").val("");
});
$("#grams").focusin(function() {
$("#percentage").val("");
$("#pounds").val("");
});
$("#percentage").focusin(function() {
$("#pounds").val("");
$("#grams").val("");
});
$(".input_field").focusin(function() {
$("#density").removeClass('highlight');
$("#sg").removeClass('highlight');
$("#pounds").removeClass('highlight');
$("#grams").removeClass('highlight');
$("#percentage").removeClass('highlight');
});
//Calculate on press of enter
$("#button").keypress(function(e) {
if (e.which == 13) {
alert("this is working");
}
});
$("#button").click(function() {
calculateButton();
});
//Calculate values on button hit
function calculateButton() {
function numberWithCommas(x) {
x = x.toString();
var pattern = /(-?\d+)(\d{3})/;
while (pattern.test(x))
x = x.replace(pattern, "$1,$2");
return x;
}
function removeCommas(x) {
x = x.replace(",", "");
return x;
}
var results = 0;
//Pulling information from input cells
var densityStr = document.getElementById("density").value;
var sgStr = document.getElementById("sg").value;
var poundsStr = document.getElementById("pounds").value;
var gramsStr = document.getElementById("grams").value;
var percentageStr = document.getElementById("percentage").value;
//remove commas from string and then convert string to number
var densityNum = Number(removeCommas(densityStr));
var sgNum = Number(removeCommas(sgStr));
var poundsNum = Number(removeCommas(poundsStr));
var gramsNum = Number(removeCommas(gramsStr));
var percentageNum = Number(removeCommas(percentageStr));
if (densityStr.length !== 0) {
var sgConversion = densityNum / 8.3454;
$("#sg").val(sgConversion.toFixed(3));
$("#density").addClass('highlight');
} else if (sgStr.length !== 0) {
var densityConversion = sgNum * 8.3454;
$("#density").val(densityConversion.toFixed(3));
$("#sg").addClass('highlight');
}
if (poundsStr.length !== 0) {
$("#pounds").addClass("highlight");
densityNum = document.getElementById("density").value;
var gramsConversion = poundsNum * 119.83;
var percentageConversion = poundsNum / densityNum * 100;
$("#grams").val(gramsConversion.toFixed(0));
$("#percentage").val(percentageConversion.toFixed(2));
} else if (gramsStr.length !== 0) {
$("#grams").addClass("highlight");
densityNum = document.getElementById("density").value;
var poundsConversion = gramsNum / 119.83;
var percentageConversion = poundsConversion / densityNum * 100;
$("#pounds").val(poundsConversion.toFixed(2));
$("#percentage").val(percentageConversion.toFixed(2));
} else if (percentageStr.length !== 0) {
$("#percentage").addClass("highlight");
densityNum = document.getElementById("density").value;
var percentageDec = percentageNum / 100;
var poundsConversion = densityNum * percentageDec;
var gramsConversion = poundsConversion * 119.83;
$("#pounds").val(poundsConversion.toFixed(2));
$("#grams").val(gramsConversion.toFixed(2));
}
}
});
body {
margin: 0;
font-family: 'Lato', sans-serif;
background: #d2d2d2;
}
p {
text-align: center;
}
conatiner {
max-width: 1024px;
margin: 0 auto;
}
#navbarContainer {
background: #F44336;
overflow: hidden;
width: 100%;
margin: 0;
}
.navbar {
float: left;
display: block;
font-family: 'Lato', sans-serif;
height: 40px;
width: 200px;
line-height: 40px;
text-align: center;
background: #F44336;
text-decoration: none;
color: #212121;
}
.navbar:hover {
background: #E57373;
color: white;
}
.active {
background: #C62828;
color: white;
}
#formContainer {
width: 450px;
background: #FDFFFC;
margin: 50px auto;
padding: 0px;
border-radius: 8px;
overflow: hidden;
}
#formContainer header {
width: 100%;
height: 130px;
background-color: #3cba54;
overflow: auto;
color: white;
}
header h1 {
margin: 35px 0 0 0;
text-align: center;
line-height: 30px;
}
header h3 {
line-height: 40px;
text-align: center;
margin: 0;
}
#heading {
background-color: #3cba54;
height: 40px;
color: white;
margin-bottom: 25px;
margin-left: -30px;
}
#heading h3 {
line-height: 40px;
}
form {
padding: 20px 0 0 20px;
text-align: center;
}
label {
display: inline-block;
width: 220px;
text-align: right;
}
#myForm .input_field {
margin-left: 20px;
margin-bottom: 10px;
font-size: 20px;
padding-left: 10px;
width: 125px;
height: 35px;
font-size: 17px;
border-radius: 3px;
background-color: #E0E0E0;
border: none;
}
#button {
display: block;
border-radius: 6px;
width: 200px;
height: 50px;
padding: 8px 15px 8px 15px;
margin: 0 auto;
margin-bottom: 50px;
font-size: 16px;
box-shadow: 0 6px #540000;
background-color: #FF3636;
border: none;
outline: none;
}
#button:active {
background-color: #B81B1B;
box-shadow: 0 1px #27496d;
transform: translateY(5px);
}
.highlight {
background: #FFEB3B !important;
}
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<div id="container">
<div id="navbarContainer">
<a class="navbar" id="62" href="https://s.codepen.io/awheat/debug/MpMrEo/yYAyLDjQWgKr">326 IAC 6-2 Tool</a>
<a class="navbar" id="63" href="https://s.codepen.io/awheat/debug/gWmazm/NQkzYnjeQZyA">326 IAC 6-3 Tool</a>
<a class="navbar active" id="voc" href="https://s.codepen.io/awheat/debug/qVpPNm/VGAWNnJYBjZr">VOC Conversion Tool</a>
</div>
<div id="formContainer">
<header>
<h1>VOC Conversion Tool</h1>
<h3>(for conversion of VOC data to other units)</h3>
</header>
<form id="myForm">
<label>Density of Coating (lbs/gal): </label><input type="text" id="density" class="input_field">
<label>Specific Graviy: </label><input type="text" id="sg" class="input_field">
<div id="heading">
<h3>VOC Content</h3>
</div>
<label>Pounds per Gallon (lbs/gal): </label><input type="text" id="pounds" class="input_field">
<label>Grams per Liter (g/L): </label><input type="text" id="grams" class="input_field">
<label>Percentage (%): </label><input type="text" id="percentage" class="input_field"><br><br>
<input type="button" id="button" value="Calculate" autofocus>
</form>
</div>
</div>
</body>
</html>
Sometimes putting script tags before the elements on the page can cause issues. You can try to put the scripts at the bottom of the body like this:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="container">
<div id="navbarContainer">
<a class="navbar" id="62" href="https://s.codepen.io/awheat/debug/MpMrEo/yYAyLDjQWgKr">326 IAC 6-2 Tool</a>
<a class="navbar" id="63" href="https://s.codepen.io/awheat/debug/gWmazm/NQkzYnjeQZyA">326 IAC 6-3 Tool</a>
<a class="navbar active" id="voc" href="https://s.codepen.io/awheat/debug/qVpPNm/VGAWNnJYBjZr">VOC Conversion Tool</a>
</div>
<div id="formContainer">
<header>
<h1>VOC Conversion Tool</h1>
<h3>(for conversion of VOC data to other units)</h3>
</header>
<form id="myForm">
<label>Density of Coating (lbs/gal): </label><input type="text" id="density" class="input_field">
<label>Specific Graviy: </label><input type="text" id="sg" class="input_field">
<div id="heading">
<h3>VOC Content</h3>
</div>
<label>Pounds per Gallon (lbs/gal): </label><input type="text" id="pounds" class="input_field">
<label>Grams per Liter (g/L): </label><input type="text" id="grams" class="input_field">
<label>Percentage (%): </label><input type="text" id="percentage" class="input_field"><br><br>
<input type="button" id="button" value="Calculate" autofocus>
</form>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
I'm trying to create a custom drop down menu, using HTML, CSS and Vanilla Javascript.
I've managed to get the menu to appear when the user clicks on the the "from" input field, however when I try and click on an option, it wont let you add the value stored in the "code" dataset.
I did get it to work by using setTimeout method, however it is a bit hit and miss sometimes and doesn't seem like a good solution.
Is there an alternative way to get it to work?
function app() {
var messages = document.querySelector(".messages");
var inputFrom = document.querySelector(".input-from");
var inputTo = document.querySelector(".input-to");
var nearestContainer = document.querySelector(".nearest-container");
inputFrom.addEventListener("focus", inputToFocusIn, false);
function inputToFocusIn(e) {
messages.innerHTML = "focusin event triggered on input-from";
// add class
inputFrom.classList.add("input-from--focusin");
nearestContainer.classList.add("nearest-container--active");
// remove class
inputFrom.classList.remove("input-from--focusout");
nearestContainer.classList.remove("nearest-container--hidden");
}
inputFrom.addEventListener("focusout", inputToFocusOut, false);
function inputToFocusOut(e) {
messages.innerHTML = "focusout event triggered on input-from";
// add class
inputFrom.classList.remove("input-from--focusin");
nearestContainer.classList.remove("nearest-container--active");
// remove class
inputFrom.classList.add("input-from--focusout");
nearestContainer.classList.add("nearest-container--hidden");
}
var nearestStations = document.querySelectorAll(".nearest-station");
// add event listener to buttons
for(var nearestStation of nearestStations) {
nearestStation.addEventListener("click", addToInputFrom, false);
}
function addToInputFrom(e) {
inputFrom.classList.add("input-from--focusout");
nearestContainer.classList.add("nearest-container--hidden");
inputFrom.classList.remove("input-from--focusin")
nearestContainer.classList.remove("nearest-container--active")
var targetDataset = e.currentTarget.dataset.code;
messages.innerHTML = "station added to input from field"
inputFrom.value = "";
inputFrom.value = targetDataset;
}
var switchButton = document.querySelector(".button-switch");
switchButton.addEventListener("click", clickSwitch, false);
function clickSwitch(e) {
var inputFromValue = inputFrom.value;
var inputToValue = inputTo.value;
inputFrom.value = inputToValue;
inputTo.value = inputFromValue;
}
}
window.onload = app();
/* stylesheet */
body {
font-family: "GRAPHIK";
font-style: normal;
font-weight: 400;
font-size: 16px;
color: #242424;
}
* {
box-sizing: border-box;
outline: none;
}
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
background-color: #FF4136;
}
.search-container {
display: flex;
flex-direction: column;
flex-shrink: 0;
width: 300px;
padding: 10px;
background-color: #FFF;
border-radius: 10px;
}
.form-container {
display: flex;
flex-direction: row;
width: 100%;
}
.input-container {
width: 100%;
}
.input {
width: 100%;
border: none;
border-radius: 10px;
background-color: #f1f1f1;
padding: 10px;
}
.input-from {
margin-bottom: 5px;
}
.input-from--focusout {
border-radius: 10px;
}
.input-from--focusin {
border-radius: 10px 10px 0 0;
}
.input-to {
margin-bottom: 5px;
}
.switch-container {
margin-bottom: 5px;
}
.button {
border: none;
background-color: transparent;
}
.button-switch {
height: 100%;
width: 38px;
margin-left: 5px;
background-color: #f1f1f1;
border-radius: 10px;
background-image: url(../assets/images/switch.svg);
background-position: center;
background-size: 20px;
background-repeat: no-repeat;
}
.button-switch:hover {
background-image: url(../assets/images/switch-hover.svg);
}
.button-search {
padding: 10px;
background-color: #2ECC40;
color: #FFF;
border-radius: 10px;
width: 100%;
transition: background-color 0.5s ease;
}
.button-search:hover {
background-color: #33e147;
}
.input-container-to {
position: relative;
}
.nearest-container {
position: absolute;
top: 38px;
background-color: #f1f1f1;
padding: 5px;
border-radius: 0 0 10px 10px;
width: 100%;
z-index: 100;
}
.messages {
width: 300px;
background-color: #FFF;
padding: 5px;
border-radius: 10px;
text-align: center;
margin-bottom: 5px;
font-size: 10px;
}
.finding, .show-more {
width: 100%;
font-size: 10px;
font-style: italic;
margin: 0;
padding: 5px;
}
.show-more {
text-align: center;
}
.nearest-station {
font-size: 10px;
padding: 5px;
border-radius: 10px;
}
.nearest-container--hidden {
display: none;
}
.nearest-station--active {
display: flex;
}
.nearest-station:hover {
background-color: #FFF;
cursor: pointer;
}
.logo {
margin-right: 5px;
}
.nr-logo {
width: 15px;
}
.station-distance {
font-style: italic;
float: right;
}
<div class="container">
<div class="messages">messages here</div>
<div class="search-container">
<div class="form-container">
<div class="input-container">
<div class="input-container-to">
<input type="text" class="input input-from" placeholder="From">
<div class="nearest-container nearest-container--hidden">
<div class="stations-container">
<p class="finding">Finding stations closest to you...</p>
<!-- stations here-->
<div class="nearest-station" data-code="Leigh-on-Sea">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Leigh-on-Sea</span>
<span class="station-distance">0.6km</span>
</div>
<div class="nearest-station" data-code="Chalkwell">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Chalkwell</span>
<span class="station-distance">1.5km</span>
</div>
<div class="nearest-station" data-code="Westcliff">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Westcliff</span>
<span class="station-distance">2.7km</span>
</div>
<div class="nearest-station" data-code="Southend Central">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Southend Central</span>
<span class="station-distance">3.6km</span>
</div>
<div class="nearest-station" data-code="Southend Victoria">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Southend Victoria</span>
<span class="station-distance">3.8km</span>
</div>
</div>
<div class="stations-show-more">
<!--
<p class="show-more">Show more stations</p> -->
</div>
</div>
</div>
<div class="input-container-to">
<input type="text" class="input input-to" placeholder="To">
</div>
</div>
<div class="switch-container">
<input type="button" class="button button-switch">
</div>
</div>
<div class="button-search-container">
<input type="button" class="button button-search" value="Search">
</div>
</div>
</div>
Using setTimeout in the inputToFocusOut() function is indeed the correct way to obtain the desired effect: hiding of the menu must be delayed so that a click on a menu item will register and its callback will fire. There should be nothing hit and miss about it, just set the delay at a reasonable value, say 300ms, and remove the hiding of the menu from the addToInputFrom() callback. Actually, you can remove all of the latter function's class-toggling calls, as they are redundant there and may interfere. The menu will be shown/hidden by virtue of inputFrom gaining/losing focus.
BTW, why are you using focusout and not blur?
Using focusout event here
inputFrom.addEventListener("focusout", inputToFocusOut, false);
is not right. Because it will be triggered before click event.
When the function inputToFocusOut is executed the .nearest-container becomes hidden:
nearestContainer.classList.add("nearest-container--hidden");
and that's why click event for it and all of its child nodes (we are interested in .nearest-station elements) won't be triggered. Instead of focusout, use mousedown event. With blur event it won't work.