Related
I am trying to make a calculator but I have the following problem:
When I type 5 + 3 = .... I get 8. That works.
However when I type - 2 = .... I get 1.
The problem happenes in the dataOperators and especially in the code "disNum2 = disNum1;"
The first time I run dataOperators.forEach the calcultae works correct.
Then I hit the equal sign and the result is correct.
After the result is calculated I press another operator followed by a number.
Then I press the equal sign again and now the variable disNum2 contains disNum1 instead of the result.
I hope that you could give me some advice.
Thanks in advance!
const myInput = document.querySelector('#result');
const myOperator = document.querySelector('#operator');
const dataNumbers = document.querySelectorAll('.dataNumber');
const dataOperators = document.querySelectorAll('.dataOperator');
const dataEquals = document.querySelector('.dataEquals');
const dataClear = document.querySelector('.dataClear');
let disNum1 = '';
let disNum2 = '';
let result = '';
let hasDot = false;
let hasZero = false;
let lastOperation = '';
dataNumbers.forEach((number) => {
number.addEventListener('click',(e) => {
const clickedNum = e.target.innerText;
if (clickedNum === '.' && !hasDot) {
hasDot = true;
} else if (clickedNum === '.' && hasDot) {
return;
}
if (clickedNum === '.' && !hasZero) {
hasZero = true;
} else if (clickedNum === '.' && hasZero) {
return;
}
disNum1 += clickedNum;
myInput.value = disNum1;
})
})
dataOperators.forEach((operation) => {
operation.addEventListener('click', (e) => {
hasDot = false;
hasZero = false;
const clickedOp = e.target.innerText
lastOperation = clickedOp;
myOperator.value = clickedOp;
disNum2 = disNum1;
disNum1 = '';
})
})
function mathOperation() {
if (lastOperation === 'x') {
result = parseFloat(disNum2) * parseFloat(disNum1);
} else if (lastOperation === "+") {
result = parseFloat(disNum2) + parseFloat(disNum1);
} else if (lastOperation === "-") {
result = parseFloat(disNum2) - parseFloat(disNum1);
} else if (lastOperation === "/") {
result = parseFloat(disNum2) / parseFloat(disNum1);
} else if (lastOperation === "%") {
result = parseFloat(disNum2) % parseFloat(disNum1);
}
}
dataEquals.addEventListener("click", () => {
hasDot = false;
hasZero = false;
mathOperation();
myInput.value = result;
})
* {
box-sizing: border-box;
}
#calculator {
width: 500px;
}
#keys {
display: flex;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
}
#numbers {
display: flex;
flex-wrap: wrap;
width: 75%;
justify-content: center;
}
#operators {
width: 25%;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
#numbers div,
#operators div {
background-color: #f1f1f1;
width: 100px;
margin: 10px;
text-align: center;
padding: 20px 0;
font-size: 30px;
cursor: pointer;
box-shadow: -1px -1px 4px rgba(0, 0, 0, 0.6) inset;
}
#numbers div {
padding: 30px 0 0 0;
}
#numbers div:active,
#operators div:active {
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6) inset;
}
#screen {
margin: 18px;
width: calc(100% - 30px);
box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.6) inset;
background-color: rgba(239, 239, 239, 0.3);
display: flex;
}
#result,
#operator {
width: 100%;
height: 100px;
padding: 20px;
font-family: 'Courier New', Courier, monospace;
font-size: 42px;
text-align: right;
border: none;
}
#operator {
width: 20%;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Calculator</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="calculator">
<div id="screen">
<input type="text" id="result" placeholder="0" value="" disabled>
<input type="text" id="operator" disabled>
</div>
<div id="keys">
<div id="numbers">
<div class="dataNumber">7</div>
<div class="dataNumber">8</div>
<div class="dataNumber">9</div>
<div class="dataNumber">4</div>
<div class="dataNumber">5</div>
<div class="dataNumber">6</div>
<div class="dataNumber">1</div>
<div class="dataNumber">2</div>
<div class="dataNumber">3</div>
<div class="dataNumber">.</div>
<div class="dataNumber">0</div>
<div class="dataEquals">=</div>
</div>
<div id="operators">
<div class="dataClear">C</div>
<div class="dataOperator">+</div>
<div class="dataOperator">-</div>
<div class="dataOperator">x</div>
<div class="dataOperator">/</div>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
When you calculate the result, you probably just need to copy the result into disNum2, see the last line of the JS:
const myInput = document.querySelector('#result');
const myOperator = document.querySelector('#operator');
const dataNumbers = document.querySelectorAll('.dataNumber');
const dataOperators = document.querySelectorAll('.dataOperator');
const dataEquals = document.querySelector('.dataEquals');
const dataClear = document.querySelector('.dataClear');
let disNum1 = '';
let disNum2 = '';
let result = '';
let hasDot = false;
let hasZero = false;
let lastOperation = '';
dataNumbers.forEach((number) => {
number.addEventListener('click',(e) => {
const clickedNum = e.target.innerText;
if (clickedNum === '.' && !hasDot) {
hasDot = true;
} else if (clickedNum === '.' && hasDot) {
return;
}
if (clickedNum === '.' && !hasZero) {
hasZero = true;
} else if (clickedNum === '.' && hasZero) {
return;
}
disNum1 += clickedNum;
myInput.value = disNum1;
})
})
dataOperators.forEach((operation) => {
operation.addEventListener('click', (e) => {
hasDot = false;
hasZero = false;
const clickedOp = e.target.innerText
lastOperation = clickedOp;
myOperator.value = clickedOp;
disNum2 = disNum1;
disNum1 = '';
})
})
function mathOperation() {
if (lastOperation === 'x') {
result = parseFloat(disNum2) * parseFloat(disNum1);
} else if (lastOperation === "+") {
result = parseFloat(disNum2) + parseFloat(disNum1);
} else if (lastOperation === "-") {
result = parseFloat(disNum2) - parseFloat(disNum1);
} else if (lastOperation === "/") {
result = parseFloat(disNum2) / parseFloat(disNum1);
} else if (lastOperation === "%") {
result = parseFloat(disNum2) % parseFloat(disNum1);
}
}
dataEquals.addEventListener("click", () => {
hasDot = false;
hasZero = false;
mathOperation();
myInput.value = result;
disNum2 = result; // Your result is now also the 2nd number.
})
* {
box-sizing: border-box;
}
#calculator {
width: 500px;
}
#keys {
display: flex;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
}
#numbers {
display: flex;
flex-wrap: wrap;
width: 75%;
justify-content: center;
}
#operators {
width: 25%;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
#numbers div,
#operators div {
background-color: #f1f1f1;
width: 100px;
margin: 10px;
text-align: center;
padding: 20px 0;
font-size: 30px;
cursor: pointer;
box-shadow: -1px -1px 4px rgba(0, 0, 0, 0.6) inset;
}
#numbers div {
padding: 30px 0 0 0;
}
#numbers div:active,
#operators div:active {
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6) inset;
}
#screen {
margin: 18px;
width: calc(100% - 30px);
box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.6) inset;
background-color: rgba(239, 239, 239, 0.3);
display: flex;
}
#result,
#operator {
width: 100%;
height: 100px;
padding: 20px;
font-family: 'Courier New', Courier, monospace;
font-size: 42px;
text-align: right;
border: none;
}
#operator {
width: 20%;
}
<div id="calculator">
<div id="screen">
<input type="text" id="result" placeholder="0" value="" disabled>
<input type="text" id="operator" disabled>
</div>
<div id="keys">
<div id="numbers">
<div class="dataNumber">7</div>
<div class="dataNumber">8</div>
<div class="dataNumber">9</div>
<div class="dataNumber">4</div>
<div class="dataNumber">5</div>
<div class="dataNumber">6</div>
<div class="dataNumber">1</div>
<div class="dataNumber">2</div>
<div class="dataNumber">3</div>
<div class="dataNumber">.</div>
<div class="dataNumber">0</div>
<div class="dataEquals">=</div>
</div>
<div id="operators">
<div class="dataClear">C</div>
<div class="dataOperator">+</div>
<div class="dataOperator">-</div>
<div class="dataOperator">x</div>
<div class="dataOperator">/</div>
</div>
</div>
</div>
And here is a delegation version
I also simplified your 0 and dot code
const myInput = document.getElementById('result');
const keys = document.getElementById("keys");
const myOperator = document.getElementById('operator');
const dataEquals = document.querySelector('.dataEquals');
const dataClear = document.querySelector('.dataClear');
let disNum1 = '';
let disNum2 = '';
let result = '';
let hasDot = false;
let hasZero = false;
let lastOperation = '';
keys.addEventListener('click', (e) => {
const tgt = e.target;
if (tgt.closest("#numbers")) {
const clickedNum = tgt.textContent;
if (clickedNum === '.') {
if (hasDot) return
else hasDot = true;
if (hasZero) return
else hasZero = true;
}
disNum1 += clickedNum;
myInput.value = disNum1;
return;
}
if (tgt.closest("#operators")) {
hasDot = false;
hasZero = false;
const clickedOp = tgt.textContent;
if (clickedOp === "C") {
myInput.value = "";
myOperator.value = "";
disNum1 = disNum2 = '';
return
}
lastOperation = clickedOp;
myOperator.value = clickedOp;
disNum2 = disNum1;
disNum1 = '';
}
})
function mathOperation() {
if (lastOperation === 'x') {
result = parseFloat(disNum2) * parseFloat(disNum1);
} else if (lastOperation === "+") {
result = parseFloat(disNum2) + parseFloat(disNum1);
} else if (lastOperation === "-") {
result = parseFloat(disNum2) - parseFloat(disNum1);
} else if (lastOperation === "/") {
result = parseFloat(disNum2) / parseFloat(disNum1);
} else if (lastOperation === "%") {
result = parseFloat(disNum2) % parseFloat(disNum1);
}
}
dataEquals.addEventListener("click", () => {
hasDot = false;
hasZero = false;
mathOperation();
myInput.value = result;
disNum2 = result; // Your result is now also the 2nd number.
})
* {
box-sizing: border-box;
}
#calculator {
width: 500px;
}
#keys {
display: flex;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
}
#numbers {
display: flex;
flex-wrap: wrap;
width: 75%;
justify-content: center;
}
#operators {
width: 25%;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
#numbers div,
#operators div {
background-color: #f1f1f1;
width: 100px;
margin: 10px;
text-align: center;
padding: 20px 0;
font-size: 30px;
cursor: pointer;
box-shadow: -1px -1px 4px rgba(0, 0, 0, 0.6) inset;
}
#numbers div {
padding: 30px 0 0 0;
}
#numbers div:active,
#operators div:active {
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6) inset;
}
#screen {
margin: 18px;
width: calc(100% - 30px);
box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.6) inset;
background-color: rgba(239, 239, 239, 0.3);
display: flex;
}
#result,
#operator {
width: 100%;
height: 100px;
padding: 20px;
font-family: 'Courier New', Courier, monospace;
font-size: 42px;
text-align: right;
border: none;
}
#operator {
width: 20%;
}
<div id="calculator">
<div id="screen">
<input type="text" id="result" placeholder="0" value="" disabled>
<input type="text" id="operator" disabled>
</div>
<div id="keys">
<div id="numbers">
<div class="dataNumber">7</div>
<div class="dataNumber">8</div>
<div class="dataNumber">9</div>
<div class="dataNumber">4</div>
<div class="dataNumber">5</div>
<div class="dataNumber">6</div>
<div class="dataNumber">1</div>
<div class="dataNumber">2</div>
<div class="dataNumber">3</div>
<div class="dataNumber">.</div>
<div class="dataNumber">0</div>
<div class="dataEquals">=</div>
</div>
<div id="operators">
<div class="dataClear">C</div>
<div class="dataOperator">+</div>
<div class="dataOperator">-</div>
<div class="dataOperator">x</div>
<div class="dataOperator">/</div>
</div>
</div>
</div>
So I'm making an Etch-a-Sketch with a range slider to change the grid size, but the slider keeps resetting to its default size (16x16) as soon as I move the mouse after changing the value (if I change the value and don't move the mouse, the size doesn't reset). For some reason this doesn't happen on Chrome: the value and grid size both change and stay that way until I change them again.
Here's the JSFiddle: https://jsfiddle.net/CamiCoding/7zpt14cs/
HTML:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Etch-a-Sketch</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div class="title">
<h1>Etch-a-Sketch</h1>
</div>
<div class="btns">
<button id="blackBtn">Black</button>
<button id="rainbowBtn">Rainbow</button>
<button id="colorBtn">Color</button>
<button id="eraserBtn">Eraser</button>
<button id="resetBtn">Reset</button>
<div class="colorPicker">
<input type="color" id="color" value="#000000">
<span>Pick a color</span>
</div>
<div class="sliderAndValue">
<input type="range" min="2" max="100" value="16" id="slider">
<p class="value">16</p>
</div>
</div>
<div class="grid">
</div>
<script src="script.js" defer></script>
</body>
</html>
CSS:
#font-face {
src: url("../fonts/sf-atarian-system.regular.ttf");
font-family: Atarian;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-family: Atarian;
background-color: #D1D1D1;
}
.title h1 {
font-size: 80px;
margin: 0px;
}
.btns {
display: flex;
flex-direction: row;
width: 700px;
height: 50px;
justify-content: space-evenly;
margin-top: 20px;
margin-bottom: 20px;
}
.btns button {
font-family: Atarian;
font-size: 24px;
height: 40px;
width: 80px;
border-radius: 5px;
transition: transform 0.2s ease-in-out;
}
.btns button:hover {
transform: scale(1.2);
}
.btns .active {
background-color: #505050;
color: white;
}
.colorPicker {
display: flex;
flex-direction: column;
align-items: center;
font-size: 20px;
}
.color span {
text-align: center;
}
#color {
width: 90px;
}
.sliderAndValue {
-webkit-appearance: none;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 24px;
}
#slider {
-webkit-appearance: none;
width: 150px;
height: 10px;
background: #000;
outline: none;
border: 4px solid gray;
border-radius: 4px;
}
/* for firefox */
#slider::-moz-range-thumb {
width: 5px;
height: 20px;
background: #000;
cursor: pointer;
border: 4px solid gray;
border-radius: 4px;
}
/* for chrome/safari */
#slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 5px;
height: 20px;
background: #000;
cursor: pointer;
border: 4px solid gray;
border-radius: 4px;
}
.cell {
border: 1px solid black;
}
.cell.active {
background-color: black;
}
.grid {
display: inline-grid;
grid-template-columns: repeat(16, 2fr);
grid-template-rows: repeat(16, 2fr);
border: 5px solid gray;
border-radius: 5px;
height: 700px;
width: 700px;
background-color: white;
}
JS:
const grid = document.querySelector('.grid');
const resetBtn = document.getElementById('resetBtn');
const eraserBtn = document.getElementById('eraserBtn');
const blackBtn = document.getElementById('blackBtn');
const colorBtn = document.getElementById('colorBtn')
const colorValue = document.getElementById('color');
const slider = document.getElementById('slider');
const sliderValue = document.querySelector('.value');
const DEFAULT_COLOR = '#000000';
const DEFAULT_MODE = 'black';
const DEFAULT_SIZE = 16;
let currentColor = DEFAULT_COLOR;
let currentMode = DEFAULT_MODE;
let mouseDown = false
document.body.onmousedown = () => (mouseDown = true)
document.body.onmouseup = () => (mouseDown = false)
function setCurrentColor(newColor) {
currentColor = newColor;
}
function setCurrentMode(newMode) {
activateButton(newMode);
currentMode = newMode;
}
blackBtn.onclick = () => setCurrentMode('black');
rainbowBtn.onclick = () => setCurrentMode('rainbow');
eraserBtn.onclick = () => setCurrentMode('eraser');
colorBtn.onclick = () => setCurrentMode('color');
resetBtn.onclick = () => createGrid();
function createGrid() {
removeCells(grid);
let val = document.getElementById('slider').value;
sliderValue.textContent = val;
grid.style.gridTemplateColumns = (`repeat(${val}, 2fr`);
grid.style.gridTemplateRows = (`repeat(${val}, 2fr`);
for(let i = 0; i < val * val; i++) {
const cell = document.createElement('div');
cell.classList.add('cell');
cell.addEventListener('mouseover', changeColor);
cell.addEventListener('mousedown', changeColor);
grid.appendChild(cell);
}
}
function activateButton(newMode) {
if (currentMode === 'rainbow') {
rainbowBtn.classList.remove('active');
} else if (currentMode === 'color') {
colorBtn.classList.remove('active');
} else if (currentMode === 'eraser') {
eraserBtn.classList.remove('active');
} else if (currentMode === 'black') {
blackBtn.classList.remove('active');
}
if (newMode === 'rainbow') {
rainbowBtn.classList.add('active');
} else if (newMode === 'color') {
colorBtn.classList.add('active');
} else if (newMode === 'eraser') {
eraserBtn.classList.add('active');
} else if (newMode === 'black') {
blackBtn.classList.add('active');
}
}
function changeColor(e) {
if (e.type === 'mouseover' && !mouseDown) return;
if (currentMode === 'rainbow') {
const randomR = Math.floor(Math.random() * 256);
const randomG = Math.floor(Math.random() * 256);
const randomB = Math.floor(Math.random() * 256);
e.target.style.backgroundColor = `rgb(${randomR}, ${randomG}, ${randomB})`;
} else if (currentMode === 'color') {
e.target.style.backgroundColor = colorValue.value;
} else if (currentMode === 'eraser') {
e.target.style.backgroundColor = '#ffffff';
} else if (currentMode === 'black') {
e.target.style.background = '#000000';
}
}
slider.addEventListener('input', function(){
let val = document.getElementById('slider').value;
sliderValue.textContent = val;
removeCells(grid);
grid.style.gridTemplateColumns = (`repeat(${val}, 2fr`);
grid.style.gridTemplateRows = (`repeat(${val}, 2fr`);
for (let i = 0; i < val * val; i++) {
const cell = document.createElement('div');
cell.classList.add('cell');
cell.addEventListener('mouseover', changeColor);
cell.addEventListener('mousedown', changeColor);
grid.appendChild(cell);
}
});
function removeCells(parent){
while(grid.firstChild){
grid.removeChild(grid.firstChild);
}
}
window.onload = () => {
createGrid(DEFAULT_SIZE);
activateButton(DEFAULT_MODE);
}
I do have another question regarding this same project, but about a different issue, please let me know if I should post a different question for it or if I should post it here too!
Thanks a lot in advance :).
I was able to track down the source of the issue, and fix it. Sounds weird, but document.body.onmousedown and document.body.onmouseup were creating the issue.
Replacing them with addEventListener seems to fix it.
I also removed some repeated code (in slider's input listener), by making maximum use of createGrid() function.
const grid = document.querySelector('.grid');
const resetBtn = document.getElementById('resetBtn');
const eraserBtn = document.getElementById('eraserBtn');
const blackBtn = document.getElementById('blackBtn');
const colorBtn = document.getElementById('colorBtn')
const colorValue = document.getElementById('color');
const slider = document.querySelector('#slider');
const sliderValue = document.querySelector('.value');
const DEFAULT_COLOR = '#000000';
const DEFAULT_MODE = 'black';
const DEFAULT_SIZE = 16;
let currentColor = DEFAULT_COLOR;
let currentMode = DEFAULT_MODE;
let mouseDown = false
document.body.addEventListener("mousedown", () => (mouseDown = true))
document.body.addEventListener("mouseup", () => (mouseDown = false))
function setCurrentColor(newColor) {
currentColor = newColor;
}
function setCurrentMode(newMode) {
activateButton(newMode);
currentMode = newMode;
}
blackBtn.onclick = () => setCurrentMode('black');
rainbowBtn.onclick = () => setCurrentMode('rainbow');
eraserBtn.onclick = () => setCurrentMode('eraser');
colorBtn.onclick = () => setCurrentMode('color');
resetBtn.onclick = () => createGrid();
function createGrid(val = 16) {
slider.value = val;
sliderValue.textContent = val;
removeCells(grid);
grid.style.gridTemplateColumns = (`repeat(${val}, 2fr`);
grid.style.gridTemplateRows = (`repeat(${val}, 2fr`);
for (let i = 0; i < val * val; i++) {
const cell = document.createElement('div');
cell.classList.add('cell');
cell.addEventListener('mouseover', changeColor);
cell.addEventListener('mousedown', changeColor);
grid.appendChild(cell);
}
}
function activateButton(newMode) {
if (currentMode === 'rainbow') {
rainbowBtn.classList.remove('active');
} else if (currentMode === 'color') {
colorBtn.classList.remove('active');
} else if (currentMode === 'eraser') {
eraserBtn.classList.remove('active');
} else if (currentMode === 'black') {
blackBtn.classList.remove('active');
}
if (newMode === 'rainbow') {
rainbowBtn.classList.add('active');
} else if (newMode === 'color') {
colorBtn.classList.add('active');
} else if (newMode === 'eraser') {
eraserBtn.classList.add('active');
} else if (newMode === 'black') {
blackBtn.classList.add('active');
}
}
function changeColor(e) {
if (e.type === 'mouseover' && !mouseDown) return;
if (currentMode === 'rainbow') {
const randomR = Math.floor(Math.random() * 256);
const randomG = Math.floor(Math.random() * 256);
const randomB = Math.floor(Math.random() * 256);
e.target.style.backgroundColor = `rgb(${randomR}, ${randomG}, ${randomB})`;
} else if (currentMode === 'color') {
e.target.style.backgroundColor = colorValue.value;
} else if (currentMode === 'eraser') {
e.target.style.backgroundColor = '#ffffff';
} else if (currentMode === 'black') {
e.target.style.background = '#000000';
}
}
slider.addEventListener('input', function(e) {
let val = parseInt(document.getElementById('slider').value);
createGrid(val);
});
function removeCells(parent) {
while (grid.firstChild) {
grid.removeChild(grid.firstChild);
}
}
window.onload = () => {
createGrid(DEFAULT_SIZE);
activateButton(DEFAULT_MODE);
}
#font-face {
src: url("../fonts/sf-atarian-system.regular.ttf");
font-family: Atarian;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-family: Atarian;
background-color: #D1D1D1;
}
.title h1 {
font-size: 80px;
margin: 0px;
}
.btns {
display: flex;
flex-direction: row;
width: 700px;
height: 50px;
justify-content: space-evenly;
margin-top: 20px;
margin-bottom: 20px;
}
.btns button {
font-family: Atarian;
font-size: 24px;
height: 40px;
width: 80px;
border-radius: 5px;
transition: transform 0.2s ease-in-out;
}
.btns button:hover {
transform: scale(1.2);
}
.btns .active {
background-color: #505050;
color: white;
}
.colorPicker {
display: flex;
flex-direction: column;
align-items: center;
font-size: 20px;
}
.color span {
text-align: center;
}
#color {
width: 90px;
}
.sliderAndValue {
-webkit-appearance: none;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 24px;
}
#slider {
-webkit-appearance: none;
width: 150px;
height: 10px;
background: #000;
outline: none;
border: 4px solid gray;
border-radius: 4px;
}
/* for firefox */
#slider::-moz-range-thumb {
width: 5px;
height: 20px;
background: #000;
cursor: pointer;
border: 4px solid gray;
border-radius: 4px;
}
/* for chrome/safari */
#slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 5px;
height: 20px;
background: #000;
cursor: pointer;
border: 4px solid gray;
border-radius: 4px;
}
.cell {
border: 1px solid black;
}
.cell.active {
background-color: black;
}
.grid {
display: inline-grid;
grid-template-columns: repeat(16, 2fr);
grid-template-rows: repeat(16, 2fr);
border: 5px solid gray;
border-radius: 5px;
height: 700px;
width: 700px;
background-color: white;
user-select: none;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Etch-a-Sketch</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div class="title">
<h1>Etch-a-Sketch</h1>
</div>
<div class="btns">
<button id="blackBtn">Black</button>
<button id="rainbowBtn">Rainbow</button>
<button id="colorBtn">Color</button>
<button id="eraserBtn">Eraser</button>
<button id="resetBtn">Reset</button>
<div class="colorPicker">
<input type="color" id="color" value="#000000">
<span>Pick a color</span>
</div>
<div class="sliderAndValue">
<input type="range" min="2" value="16" id="slider">
<p class="value">16</p>
</div>
</div>
<div class="grid">
</div>
<script src="script.js" defer></script>
</body>
</html>
I've built a simple calculator using JS for the sake of practice. However, I am unable to achieve the following:
After my calculator displays the result and when I click on the keys to enter a new value, the new values keep concatenating with the result. How do I reset the display value?
How do I restrict decimal point from being entered more than ones.
Source code:
const calculator = document.querySelector(".calculator");
const displayScreen = document.querySelector(".calculatorDisplay");
const numberKeys = document.querySelectorAll(".numKeys");
const operatorKeys = document.querySelectorAll(".operator");
const equalsButton = document.querySelector(".equals");
const allClear = document.querySelector(".allClear");
const decimalButton = document.querySelector(".decimalButton");
// variables
var firstOperand;
var secondOperand;
var operator;
for(var i=0; i<numberKeys.length; i++){
numberKeys[i].addEventListener("click", e=>{
const firstValue = e.target.textContent;
displayScreen.value+= firstValue;
});
}
for(var i=0; i<operatorKeys.length; i++){
operatorKeys[i].addEventListener("click", e=>{
firstOperand = displayScreen.value;
displayScreen.value = "";
operator = e.target.textContent;
});
}
equalsButton.addEventListener("click", function(){
secondOperand = displayScreen.value;
displayScreen.value = mathOperations();
});
allClear.addEventListener("click", function(){
displayScreen.value ="";
});
decimalButton.addEventListener("click", e=>{
displayScreen.value=displayScreen.value + "."
});
function mathOperations(){
let operandOne = parseFloat(firstOperand);
let operandTwo = parseFloat(secondOperand);
if(operator==="+"){
return (operandOne + operandTwo);
}
if(operator==="-"){
return (operandOne - operandTwo);
}
if(operator==="*"){
return (operandOne * operandTwo);
}
if(operator==="/"){
return (operandOne / operandTwo);
}
}
You need to declare currentValue as a global variable (next to operator for example). Then, when user clicks on equalsButton, you set currentValue to true. Then, in numberKeys handler, add a check if currentValue is true, clear displayScreen.
numberKeys[i].addEventListener("click", e => {
if (currentValue) {
displayScreen.value = '';
currentValue = false;
}
displayScreen.value += e.target.textContent;
});
I thought by mistake that displayScreen is a string, but it's the input, so the check should be displayScreen.value.length
if (displayScreen.value.charAt(displayScreen.value.length - 1) !== '.') {
const calculator = document.querySelector(".calculator");
const displayScreen = document.querySelector(".calculatorDisplay");
const numberKeys = document.querySelectorAll(".numKeys");
const operatorKeys = document.querySelectorAll(".operator");
const equalsButton = document.querySelector(".equals");
const allClear = document.querySelector(".allClear");
const decimalButton = document.querySelector(".decimalButton");
let firstOperand;
let secondOperand;
let operator;
let currentValue = false;
enterNumbers();
for (var i = 0; i < operatorKeys.length; i++) {
operatorKeys[i].addEventListener("click", e => {
firstOperand = displayScreen.value;
displayScreen.value = "";
operator = e.target.textContent;
});
}
decimalButton.addEventListener("click", e => {
if (displayScreen.value.charAt(displayScreen.value.length - 1) !== '.') {
displayScreen.value=displayScreen.value + ".";
}
});
equalsButton.addEventListener("click", function() {
currentValue = true;
secondOperand = displayScreen.value;
displayScreen.value = mathOperations();
});
allClear.addEventListener("click", function() {
displayScreen.value = "";
});
function mathOperations() {
let operandOne = parseFloat(firstOperand);
let operandTwo = parseFloat(secondOperand);
if (operator === "+") {
return operandOne + operandTwo;
}
if (operator === "-") {
return operandOne - operandTwo;
}
if (operator === "*") {
return operandOne * operandTwo;
}
if (operator === "/") {
return operandOne / operandTwo;
}
}
function enterNumbers() {
for (var i = 0; i < numberKeys.length; i++) {
numberKeys[i].addEventListener("click", e => {
if (currentValue) {
displayScreen.value = '';
currentValue = false;
}
displayScreen.value += e.target.textContent;
});
}
}
/* Code from freshman.tech by Ayooluwa Isaiah */
html {
font-size: 62.5%;
box-sizing: border-box;
}
h1 {
text-align: center;
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
.calculator {
border: 1px solid black;
border-radius: 25px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400px;
}
.calculatorDisplay {
text-align: right;
font-size: 5rem;
width: 100%;
height: 80px;
border: none;
background-color: #252525;
color: #fff;
text-align: right;
padding-right: 20px;
padding-left: 10px;
}
button {
height: 60px;
border-radius: 3px;
border: 1px solid #c4c4c4;
background-color: transparent;
font-size: 2rem;
color: #333;
background-image: linear-gradient(
to bottom,
transparent,
transparent 50%,
rgba(0, 0, 0, 0.04)
);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05),
inset 0 1px 0 0 rgba(255, 255, 255, 0.45),
inset 0 -1px 0 0 rgba(255, 255, 255, 0.15),
0 1px 0 0 rgba(255, 255, 255, 0.15);
text-shadow: 0 1px rgba(255, 255, 255, 0.4);
}
button:hover {
background-color: #eaeaea;
}
.operator {
color: #337cac;
}
.allClear {
background-color: #f0595f;
border-color: #b0353a;
color: #fff;
}
.allClear:hover {
background-color: #f17377;
}
.equals {
background-color: #2e86c0;
border-color: #337cac;
color: #fff;
height: 100%;
grid-area: 2 / 4 / 6 / 5;
}
.equals:hover {
background-color: #4e9ed4;
}
.calculatorKeys {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-gap: 20px;
padding: 20px;
}
<!DOCTYPE html>
<html>
<head>
<title>Calculator</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>My Calculator</h1>
<div class="calculator">
<input type="text" name="display" class="calculatorDisplay">
<div class=calculatorKeys>
<!-- operators -->
<button class="operator">+</button>
<button class="operator">-</button>
<button class="operator">*</button>
<button class="operator">/</button>
<button class="numKeys">7</button>
<button class="numKeys">8</button>
<button class="numKeys">9</button>
<button class="numKeys">4</button>
<button class="numKeys">5</button>
<button class="numKeys">6</button>
<button class="numKeys">1</button>
<button class="numKeys">2</button>
<button class="numKeys">3</button>
<button class="numKeys">0</button>
<!-- decimal-->
<button class="decimalButton">.</button>
<!-- All clear -->
<button class="allClear">AC</button>
<!-- result -->
<button class="equals">=</button>
</div>
<script type="text/javascript" src="cal.js"></script>
</div>
</body>
</html>
https://codepen.io/moshfeu/pen/RwPQKJV?editors=1000
I have got a problem at the coding project I am doing, as I formatted the numbers to be shown nicer, I ran into a problem. The webpage when it loads shows NaN. undefined in the total income/expenses at the top. I can't figure out what is the problem.
//Budget controller
var budgetController = (function() {
var Expense = function(id, description, value) {
this.id = id;
this.description = description;
this.value = value;
this.percentage = -1;
};
Expense.prototype.calcPercentage = function(totalIncome) {
if (totalIncome > 0) {
this.percentage = Math.round((this.value / totalIncome) * 100);
} else {
this.percentage = -1;
}
};
Expense.prototype.getPercentage = function() {
return this.percentage;
};
var Income = function(id, description, value) {
this.id = id;
this.description = description;
this.value = value;
};
var calculateTotal = function(type) {
var sum = 0;
data.allItems[type].forEach(function(cur) {
sum = sum + cur.value;
});
data.totals[type] = sum;
};
var data = {
allItems: {
exp: [],
inc: []
},
totals: {
exp: 0,
inc: 0
},
budget: 0,
percentage: -1
};
return {
addItem: function(type, des, val) {
var newItem, ID;
//create new iD
if (data.allItems[type].length > 0) {
ID = data.allItems[type][data.allItems[type].length - 1].id + 1;
} else {
ID = 0;
}
//CREATe new item, if it is inc or exp
if (type === 'exp') {
newItem = new Expense(ID, des, val);
} else if (type === 'inc') {
newItem = new Income(ID, des, val);
}
// Push all items into data structure and return the new element
data.allItems[type].push(newItem);
return newItem;
},
deleteItem: function(type, id) {
var ids, index;
ids = data.allItems[type].map(function(current) {
return current.id;
});
index = ids.indexOf(id);
if (index !== -1) {
data.allItems[type].splice(index, 1);
}
},
calculateBudget: function() {
// calculate the total income and expenses
calculateTotal('exp');
calculateTotal('inc');
// calculate the budget: income - expenses
data.budget = data.totals.inc - data.totals.exp;
if (data.totals.inc > 0) {
data.percentage = Math.round((data.totals.exp / data.totals.inc) * 100);
} else {
data.percentage = -1;
}
},
calculatePercentages: function() {
data.allItems.exp.forEach(function(cur) {
cur.calcPercentage(data.totals.inc);
});
},
getPercentages: function() {
var allPerc = data.allItems.exp.map(function(cur) {
return cur.getPercentage();
});
return allPerc;
},
getBudget: function() {
return {
budget: data.budget,
totalInc: data.totals.inc,
totalExp: data.totals.exp,
percentage: data.percentage
};
}
};
})();
// UI Controller
var UIController = (function() {
var DOMstrings = {
inputType: '.add__type',
inputDescription: '.add__description',
inputValue: '.add__value',
inputBtn: '.add__btn',
incomeContainer: '.income__list',
expensesContainer: '.expenses__list',
budgetLabel: '.budget__value',
incomeLabel: '.budget__income--value',
expensesLabel: '.budget__expenses--value',
percentageLabel: '.budget__expenses--percentage',
container: '.container',
expensesPercLabel: '.item__percentage',
dateLabel: '.budget__title--month'
};
var formatNumber = function(num, type) {
var numSplit, int, dec, type;
/* + or - befofe a number
on 2 decimals
comma seperating thousands
*/
num = Math.abs(num);
num = num.toFixed(2);
numSplit = num.split('.');
int = numSplit[0];
if (int.length > 3) {
int = int.substr(0, int.length - 3) + ',' + int.substr(int.length - 3, 3); //input 23510, output 23,510
}
dec = numSplit[1];
return (type === 'exp' ? '-' : '+') + ' ' + int + '.' + dec;
};
var nodeListForEach = function(list, callback) {
for (var i = 0; i < list.length; i++) {
callback(list[i], i);
}
};
return {
getInput: function() {
return {
type: document.querySelector(DOMstrings.inputType).value, //will be either inc or exp
description: document.querySelector(DOMstrings.inputDescription).value,
value: parseFloat(document.querySelector(DOMstrings.inputValue).value)
};
},
addListItem: function(obj, type) {
var html, newHtml, element;
// Create HTML string with placeholder text
if (type === 'inc') {
element = DOMstrings.incomeContainer;
html = '<div class="item clearfix" id="inc-%id%"> <div class="item__description">%description%</div><div class="right clearfix"><div class="item__value">%value%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>';
} else if (type === 'exp') {
element = DOMstrings.expensesContainer;
html = '<div class="item clearfix" id="exp-%id%"><div class="item__description">%description%</div><div class="right clearfix"><div class="item__value">%value%</div><div class="item__percentage">21%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>';
}
// Replace the placeholder text with some actual data
newHtml = html.replace('%id%', obj.id);
newHtml = newHtml.replace('%description%', obj.description);
newHtml = newHtml.replace('%value%', formatNumber(obj.value, type));
// Insert the HTML into the DOM
document.querySelector(element).insertAdjacentHTML('beforeend', newHtml);
},
deleteListItem: function(selectorID) {
var el = document.getElementById(selectorID);
el.parentNode.removeChild(el);
},
clearFields: function() {
var fields, fieldsArr;
fields = document.querySelectorAll(
DOMstrings.inputDescription + ',' + DOMstrings.inputValue
);
fieldsArr = Array.prototype.slice.call(fields);
fieldsArr.forEach(function(current, index, array) {
current.value = "";
});
fieldsArr[0].focus();
},
displayBudget: function(obj) {
var type;
obj.budget > 0 ? type = 'inc' : type = 'exp';
document.querySelector(DOMstrings.budgetLabel).textContent = formatNumber(obj.budget, type);
document.querySelector(DOMstrings.incomeLabel).textContent = formatNumber(obj.totalInc, 'inc');
document.querySelector(DOMstrings.expensesLabel).textContent = formatNumber(obj.totalExp, 'exp');
if (obj.percentage > 0) {
document.querySelector(DOMstrings.percentageLabel).textContent = obj.percentage + '%';
} else {
document.querySelector(DOMstrings.percentageLabel).textContent = '---';
}
},
displayPercentages: function(percentages) {
var fields = document.querySelectorAll(DOMstrings.expensesPercLabel);
nodeListForEach(fields, function(current, index) {
if (percentages[index] > 0) {
current.textContent = percentages[index] + '%';
} else {
current.textContent = '---';
}
});
},
getDOMstrings: function() {
return DOMstrings;
}
};
})();
// App Controller - global
var controller = (function(budgetCtrl, UICtrl) {
var setupEventListeners = function() {
var DOM = UICtrl.getDOMstrings();
document.querySelector(DOM.inputBtn).addEventListener('click', ctrlAddItem);
document.addEventListener('keypress', function(event) {
if (event.keyCode === 13 || event.which === 13) {
ctrlAddItem();
}
});
document.querySelector(DOM.container).addEventListener('click', ctrlDeleteItem);
};
var updateBudget = function() {
// 1. Calculate the budget
budgetCtrl.calculateBudget();
// 2. Return the budget
var budget = budgetCtrl.getBudget();
// 3. Display the budget on the UI
UICtrl.displayBudget(budget);
};
var updatePercentages = function() {
// 1. Calculate percentages
budgetCtrl.calculatePercentages();
// 2. Read percentages from the budget controller
var percentages = budgetCtrl.getPercentages();
// 3. Update the UI with the new percentages
UICtrl.displayPercentages(percentages);
};
var ctrlAddItem = function() {
var input, newItem;
// 1. Get the field input data
input = UICtrl.getInput();
if (input.description !== "" && !isNaN(input.value) && input.value > 0) {
// 2. Add the item to the budget controller
newItem = budgetCtrl.addItem(input.type, input.description, input.value);
// 3. Add the item to the UI
UICtrl.addListItem(newItem, input.type);
// 4. Clear the fields
UICtrl.clearFields();
// 5. Calculate and update budget
updateBudget();
// 6. Calculate and update percentages
updatePercentages();
}
};
var ctrlDeleteItem = function(event) {
var itemID, splitID, type, ID;
itemID = event.target.parentNode.parentNode.parentNode.parentNode.id;
if (itemID) {
//inc-1
splitID = itemID.split('-');
type = splitID[0];
ID = parseInt(splitID[1]);
// 1. delete the item from the data structure
budgetCtrl.deleteItem(type, ID);
// 2. Delete the item from the UI
UICtrl.deleteListItem(itemID);
// 3. Update and show the new budget
updateBudget();
// 4. Calculate and update percentages
updatePercentages();
}
};
return {
init: function() {
console.log('App has started');
UICtrl.displayBudget({
budget: 0,
totalIncome: 0,
totalExpenses: 0,
percentage: -1
});
setupEventListeners();
}
};
})(budgetController, UIController);
controller.init();
/**********************************************
*** GENERAL
**********************************************/
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.clearfix::after {
content: "";
display: table;
clear: both;
}
body {
color: #555;
font-family: Open Sans;
font-size: 16px;
position: relative;
height: 100vh;
font-weight: 400;
}
.right {
float: right;
}
.red {
color: #FF5049 !important;
}
.red-focus:focus {
border: 1px solid #FF5049 !important;
}
/**********************************************
*** TOP PART
**********************************************/
.top {
height: 40vh;
background-image: linear-gradient(rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.35)), url(back.png);
background-size: cover;
background-position: center;
position: relative;
}
.budget {
position: absolute;
width: 350px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #fff;
}
.budget__title {
font-size: 18px;
text-align: center;
margin-bottom: 10px;
font-weight: 300;
}
.budget__value {
font-weight: 300;
font-size: 46px;
text-align: center;
margin-bottom: 25px;
letter-spacing: 2px;
}
.budget__income,
.budget__expenses {
padding: 12px;
text-transform: uppercase;
}
.budget__income {
margin-bottom: 10px;
background-color: #28B9B5;
}
.budget__expenses {
background-color: #FF5049;
}
.budget__income--text,
.budget__expenses--text {
float: left;
font-size: 13px;
color: #444;
margin-top: 2px;
}
.budget__income--value,
.budget__expenses--value {
letter-spacing: 1px;
float: left;
}
.budget__income--percentage,
.budget__expenses--percentage {
float: left;
width: 34px;
font-size: 11px;
padding: 3px 0;
margin-left: 10px;
}
.budget__expenses--percentage {
background-color: rgba(255, 255, 255, 0.2);
text-align: center;
border-radius: 3px;
}
/**********************************************
*** BOTTOM PART
**********************************************/
/***** FORM *****/
.add {
padding: 14px;
border-bottom: 1px solid #e7e7e7;
background-color: #f7f7f7;
}
.add__container {
margin: 0 auto;
text-align: center;
}
.add__type {
width: 55px;
border: 1px solid #e7e7e7;
height: 44px;
font-size: 18px;
color: inherit;
background-color: #fff;
margin-right: 10px;
font-weight: 300;
transition: border 0.3s;
}
.add__description,
.add__value {
border: 1px solid #e7e7e7;
background-color: #fff;
color: inherit;
font-family: inherit;
font-size: 14px;
padding: 12px 15px;
margin-right: 10px;
border-radius: 5px;
transition: border 0.3s;
}
.add__description {
width: 400px;
}
.add__value {
width: 100px;
}
.add__btn {
font-size: 35px;
background: none;
border: none;
color: #28B9B5;
cursor: pointer;
display: inline-block;
vertical-align: middle;
line-height: 1.1;
margin-left: 10px;
}
.add__btn:active {
transform: translateY(2px);
}
.add__type:focus,
.add__description:focus,
.add__value:focus {
outline: none;
border: 1px solid #28B9B5;
}
.add__btn:focus {
outline: none;
}
/***** LISTS *****/
.container {
width: 1000px;
margin: 60px auto;
}
.income {
float: left;
width: 475px;
margin-right: 50px;
}
.expenses {
float: left;
width: 475px;
}
h2 {
text-transform: uppercase;
font-size: 18px;
font-weight: 400;
margin-bottom: 15px;
}
.icome__title {
color: #28B9B5;
}
.expenses__title {
color: #FF5049;
}
.item {
padding: 13px;
border-bottom: 1px solid #e7e7e7;
}
.item:first-child {
border-top: 1px solid #e7e7e7;
}
.item:nth-child(even) {
background-color: #f7f7f7;
}
.item__description {
float: left;
}
.item__value {
float: left;
transition: transform 0.3s;
}
.item__percentage {
float: left;
margin-left: 20px;
transition: transform 0.3s;
font-size: 11px;
background-color: #FFDAD9;
padding: 3px;
border-radius: 3px;
width: 32px;
text-align: center;
}
.income .item__value,
.income .item__delete--btn {
color: #28B9B5;
}
.expenses .item__value,
.expenses .item__percentage,
.expenses .item__delete--btn {
color: #FF5049;
}
.item__delete {
float: left;
}
.item__delete--btn {
font-size: 22px;
background: none;
border: none;
cursor: pointer;
display: inline-block;
vertical-align: middle;
line-height: 1;
display: none;
}
.item__delete--btn:focus {
outline: none;
}
.item__delete--btn:active {
transform: translateY(2px);
}
.item:hover .item__delete--btn {
display: block;
}
.item:hover .item__value {
transform: translateX(-20px);
}
.item:hover .item__percentage {
transform: translateX(-20px);
}
.unpaid {
background-color: #FFDAD9 !important;
cursor: pointer;
color: #FF5049;
}
.unpaid .item__percentage {
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.1);
}
.unpaid:hover .item__description {
font-weight: 900;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:100,300,400,600" rel="stylesheet" type="text/css">
<link href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css">
<link type="text/css" rel="stylesheet" href="style.css">
<title>Budgety</title>
</head>
<body>
<div class="top">
<div class="budget">
<div class="budget__title">
Available Budget in <span class="budget__title--month">%Month%</span>:
</div>
<div class="budget__value">+ 2,345.64</div>
<div class="budget__income clearfix">
<div class="budget__income--text">Income</div>
<div class="right">
<div class="budget__income--value">+ 4,300.00</div>
<div class="budget__income--percentage"> </div>
</div>
</div>
<div class="budget__expenses clearfix">
<div class="budget__expenses--text">Expenses</div>
<div class="right clearfix">
<div class="budget__expenses--value">- 1,954.36</div>
<div class="budget__expenses--percentage">45%</div>
</div>
</div>
</div>
</div>
<div class="bottom">
<div class="add">
<div class="add__container">
<select class="add__type">
<option value="inc" selected>+</option>
<option value="exp">-</option>
</select>
<input type="text" class="add__description" placeholder="Add description">
<input type="number" class="add__value" placeholder="Value">
<button class="add__btn"><i class="ion-ios-checkmark-outline"></i></button>
</div>
</div>
<div class="container clearfix">
<div class="income">
<h2 class="icome__title">Income</h2>
<div class="income__list">
<!--
<div class="item clearfix" id="income-0">
<div class="item__description">Salary</div>
<div class="right clearfix">
<div class="item__value">+ 2,100.00</div>
<div class="item__delete">
<button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
</div>
</div>
</div>
<div class="item clearfix" id="income-1">
<div class="item__description">Sold car</div>
<div class="right clearfix">
<div class="item__value">+ 1,500.00</div>
<div class="item__delete">
<button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
</div>
</div>
</div>
-->
</div>
</div>
<div class="expenses">
<h2 class="expenses__title">Expenses</h2>
<div class="expenses__list">
<!--
<div class="item clearfix" id="expense-0">
<div class="item__description">Apartment rent</div>
<div class="right clearfix">
<div class="item__value">- 900.00</div>
<div class="item__percentage">21%</div>
<div class="item__delete">
<button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
</div>
</div>
</div>
<div class="item clearfix" id="expense-1">
<div class="item__description">Grocery shopping</div>
<div class="right clearfix">
<div class="item__value">- 435.28</div>
<div class="item__percentage">10%</div>
<div class="item__delete">
<button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
</div>
</div>
</div>
-->
</div>
</div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
The problem is that in the function formatNumber, the value num is not initialized at first time. For solving this, you can put a default value when the value of num is empty, like this:
var formatNumber = function(num = 0, type = '') {
var numSplit, int, dec, type;
/* + or - befofe a number
on 2 decimals
comma seperating thousands
*/
num = Math.abs(num);
num = num.toFixed(2);
numSplit = num.split('.');
int = numSplit[0];
if (int.length > 3) {
int = int.substr(0, int.length - 3) + ',' + int.substr(int.length - 3, 3); //input 23510, output 23,510
}
dec = numSplit[1];
return (type === 'exp' ? '-' : '+') + ' ' + int + '.' + dec;
};
I am teaching myself JavaScript and to improve my programming logic I decided to make a Hangman game. Everything works but I am having a problem with the win or lose function. The logic is If the indexCompare array length is === to correctGuesses Array length. Display You win If your lives are === to 0 Display you lose. But for some reason when a correct guess is pushed to the correctGuesses Array if it is a letter that appears more then once in the word. Only 1 occurrence of that letter is added to the array. So certain words never result in a win. And the win condition is never fulfilled. And I think it has something to do with me getting the value from the event Object. I might be wrong though. Any help would be greatly appreciated.
var gameCore = window.onload = function() {
var hangmanWords = ["super", "venus", "spanish", "darkness", "tenebris", "meatball", "human", "omega", "alpha", "isochronism", "supercalifragilisticexpialidocious"];
var commentsArray = ["I belive in you! You can do the thing!", "There is still hope keep trying", "Third times a charm", "You can do this", "Think player think! The counter is almost out", "Never give up", "The last melon 0.0", "What the frog you had one job u_u"];
var hints = ["The opposite of ordinary.", "A planet in are solar system.", "One of the largest languages in the world", "The opposite of light", "A rare word for darkness", "A tasty kind of sphear AKA 'ball' ", "You are A?", "A letter in the greek alphabet.", "Another letter in the greek alphabet.", "A word about time that almost no one uses.", "A big word that you know if you have seen mary poppins but never use."]
var correctGuesses = [];
var lives = 7;
var indexCompare = [];
var choosenWord = []
var arrayCounter = [];
//get elements
var showHint = document.getElementById("hint");
var showLivesLeft = document.getElementById("lives");
var showComments = document.getElementById("comment");
var showLoseOrWin = document.getElementById("winOrLoseDisplay");
// click assigner function
var clickAssigner = function(event) {
var letterHandler = document.getElementsByClassName("letters");
for (var i = 0; i < letterHandler.length; i++) {
letterHandler[i].addEventListener("click", compare, false);
}
var hintHandler = document.getElementById("hint");
hintHandler.addEventListener("click", hint, false);
}
clickAssigner(event);
function hint(event) {
if (arrayCounter[0] === 0) {
showHint.innerHTML = hints[arrayCounter]
};
if (arrayCounter[0] === 1) {
showHint.innerHTML = hints[arrayCounter]
};
if (arrayCounter[0] === 2) {
showHint.innerHTML = hints[arrayCounter]
};
if (arrayCounter[0] === 3) {
showHint.innerHTML = hints[arrayCounter]
};
if (arrayCounter[0] === 4) {
showHint.innerHTML = hints[arrayCounter]
};
if (arrayCounter[0] === 5) {
showHint.innerHTML = hints[arrayCounter]
};
if (arrayCounter[0] === 6) {
showHint.innerHTML = hints[arrayCounter]
};
if (arrayCounter[0] === 7) {
showHint.innerHTML = hints[arrayCounter]
};
if (arrayCounter[0] === 8) {
showHint.innerHTML = hints[arrayCounter]
};
if (arrayCounter[0] === 9) {
showHint.innerHTML = hints[arrayCounter]
};
if (arrayCounter[0] === 10) {
showHint.innerHTML = hints[arrayCounter]
};
}
// word selector and display function
// arrayCounter is the same as i
function wordSelector() {
var randomNumber = Math.floor(Math.random() * (10 - 0 + 1)) + 0;
arrayCounter.push(randomNumber);
var livesContainer = document.createElement("p");
var livesNumber = lives;
showLivesLeft.setAttribute("id", "livesNumbers");
showLivesLeft.appendChild(livesContainer);
livesContainer.innerHTML = livesNumber;
var selectedWord = hangmanWords[arrayCounter];
var wordDisplay = document.getElementById("wordDisplay");
var correctWordDisplay = document.createElement("ul");
var playerGuess;
for (var i = 0; i < selectedWord.length; i++) {
correctWordDisplay.setAttribute("id", "correctWordDisplay-UL");
playerGuess = document.createElement("li");
playerGuess.setAttribute("class", "playerGuess");
playerGuess.innerHTML = "_";
indexCompare.push(playerGuess);
wordDisplay.appendChild(correctWordDisplay);
correctWordDisplay.appendChild(playerGuess);
}
}
wordSelector();
// compare function // decrement lives function // remove health bar
function compare(event) {
var livesDisplay = document.getElementById("livesNumbers");
var btnVal = event.target.value;
var word = hangmanWords[arrayCounter];
for (var i = 0; i < word.length; i++) {
if (word[i] === btnVal) {
indexCompare[i].innerHTML = btnVal;
}
}
var c = word.indexOf(btnVal);
if (c === -1) {
event.target.removeAttribute("letters");
event.target.setAttribute("class", "incorrectLetter");
event.target.removeEventListener("click", compare);
lives -= 1;
livesDisplay.innerHTML = lives;
} else {
event.target.removeAttribute("letters");
event.target.setAttribute("class", "correctLetter");
event.target.removeEventListener("click", compare);
correctGuesses.push(event.target.value);
}
comments();
winOrLose();
// console.log(event);
// console.log(word);
}
// comment function
function comments() {
if (lives === 7) {
showComments.innerHTML = "<p>" + commentsArray[0] + "</p>"
};
if (lives === 6) {
showComments.innerHTML = "<p>" + commentsArray[1] + "</p>"
};
if (lives === 5) {
showComments.innerHTML = "<p>" + commentsArray[2] + "</p>"
};
if (lives === 4) {
showComments.innerHTML = "<p>" + commentsArray[3] + "</p>"
};
if (lives === 3) {
showComments.innerHTML = "<p>" + commentsArray[4] + "</p>"
};
if (lives === 2) {
showComments.innerHTML = "<p>" + commentsArray[5] + "</p>"
};
if (lives === 1) {
showComments.innerHTML = "<p>" + commentsArray[6] + "</p>"
};
if (lives === 0) {
showComments.innerHTML = "<p>" + commentsArray[7] + "</p>"
};
}
// win or lose function
function winOrLose() {
for (var i = 0; i < indexCompare.length; i++) {
if (indexCompare.length === correctGuesses.length) {
showLoseOrWin.innerHTML = "<p>" + "YOU WIN!!! :D" + "</p>";
}
}
if (lives === 0) {
showLoseOrWin.innerHTML = "<p>" + "YOU LOSE u_u" + "</p>";
}
}
function reset() {
}
}
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html,body,div,span,applet,object,iframe,h1,h2,
h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,
img,ins,kbd,q,
s,samp,small,strike,strong,sub,sup,tt,var,b,u,
i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,
legend,table,caption,tbody,tfoot,thead,tr,th,
td,article,aside,canvas,details,embed,figure,figcaption,
footer,header,hgroup,menu,nav,output,ruby,section,
summary,time,mark,audio,video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section {
display: block;
}
body {
line-height: 1;
}
ol,ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
#container {
overflow: hidden;
max-width: 60%;
background-color: yellowgreen;
margin: 7em auto;
padding: 1em;
}
#wordDisplay {
height: 6em;
background-color: orangered;
margin-bottom: 0.2em;
text-align: center;
padding-top: 2.4em;
font-size: 26px;
display: flex;
justify-content: center;
}
#correctWordDisplay-UL {
list-style: none;
display: flex;
justify-content: center;
}
.playerGuess {
margin: 0em 0.08em;
font-size: 30px;
}
#hint {
max-width: 26em;
padding: 1em;
background-color: skyblue;
border: 0.5em ridge gold;
font-weight: 900;
margin: 0em auto 1em auto;
text-align: center;
}
#hint:hover {
background-color: coral;
cursor: pointer;
font-style: oblique;
}
#letterDiplay {
width: 14em;
float: left;
text-align: center;
background: crimson;
padding: 1em;
}
.letters {
margin: 0.3em auto;
text-align: center;
width: 4em;
height: 3em;
font-weight: 900;
background-color: darkorange;
border: 3px ridge darkblue;
}
.letters:hover {
background: steelblue;
color: white;
cursor: pointer;
}
#theChanceCounter {
text-align: center;
float: right;
width: 14em;
background-color: crimson;
height: 28.9em;
}
/* #lives{
width: 3em;
height: 3em;
margin: 1em auto 0em auto;
background-color: teal;
color: black;
font-weight: 900;
text-align: center;
} */
#livesNumbers {
margin-top: 1em;
border: 3px solid black;
width: 3em;
height: 3em;
padding: 0.9em 0em 0em 0em;
margin: 1em auto 0em auto;
background-color: teal;
color: black;
font-weight: 900;
text-align: center;
}
.correctLetter {
margin: 0.3em auto;
text-align: center;
width: 4em;
height: 3em;
font-weight: 900;
background: green;
color: yellow;
}
.incorrectLetter {
margin: 0.3em auto;
text-align: center;
width: 4em;
height: 3em;
font-weight: 900;
background: red;
color: yellow;
}
#comment {
background-color: forestgreen;
width: 12em;
height: 4em;
padding: 1em 0.4em 0em 0.4em;
margin: 0.3em auto 0.3em auto;
border: 3px solid black;
}
#winOrLoseDisplay {
width: 18em;
padding: 1em;
background-color: skyblue;
border: 0.5em ridge orange;
font-weight: 900;
margin: 0em auto 1em 1.4em;
text-align: center;
float: left;
}
<div id="container">
<section id="wordDisplay">
</section>
<section id="hint">Click for hint.</section>
<section id="letterDiplay">
<button class="letters" value="a">A</button>
<button class="letters" value="b">B</button>
<button class="letters" value="c">C</button>
<button class="letters" value="d">D</button>
<button class="letters" value="e">E</button>
<button class="letters" value="f">F</button>
<button class="letters" value="g">G</button>
<button class="letters" value="h">H</button>
<button class="letters" value="i">I</button>
<button class="letters" value="j">J</button>
<button class="letters" value="k">K</button>
<button class="letters" value="l">L</button>
<button class="letters" value="m">M</button>
<button class="letters" value="n">N</button>
<button class="letters" value="o">O</button>
<button class="letters" value="p">P</button>
<button class="letters" value="q">Q</button>
<button class="letters" value="r">R</button>
<button class="letters" value="s">S</button>
<button class="letters" value="t">T</button>
<button class="letters" value="u">U</button>
<button class="letters" value="v">V</button>
<button class="letters" value="w">W</button>
<button class="letters" value="x">X</button>
<button class="letters" value="y">Y</button>
<button class="letters" value="z">Z</button>
</section>
<section id="winOrLoseDisplay"></section>
<section id="theChanceCounter">
<div id="lives">
</div>
<div id="comment">
</div>
</section>
</div>
</script>