I am new to programming and I am trying to make a calculator by using html and js. I want the calculator to look like a real-life calculator so when I click the number button, the number will show in the block. I have made this function, but I can't clear the number shown on block by clicking "AC" button. What should I change to make the clear function work.
part of html code
<tr><td colspan="5" id="result" height="40"></td></tr>
<tr>
<td id="seven" onclick = "output()">7</td>
<td id="eight" onclick = "output()">8</td>
<td id="nine" onclick = "output()">9</td>
<td id="C" >C</td>
<td id="AC" onclick = "clear()">AC</td>
</tr>
js code
let result = document.getElementById("result");
function output() {
result.innerHTML = result.innerHTML event.target.innerHTML;
};
function clear() {
result.innerHTML = "";
};
I tried the clear function to clear the innerhtml but it didn't work. Should I change the code or there is a problem of the output function. How to use the clear fucntion to clear the output displayed.
Stack Snippet
let result = document.getElementById("result");
function output() {
result.innerHTML = result.innerHTML event.target.innerHTML;
};
function clear() {
result.innerHTML = "";
};
<table>
<tr><td colspan="5" id="result" height="40"></td></tr>
<tr>
<td id="seven" onclick = "output()">7</td>
<td id="eight" onclick = "output()">8</td>
<td id="nine" onclick = "output()">9</td>
<td id="C" >C</td>
<td id="AC" onclick = "clear()">AC</td>
</tr>
</table>
CodePudding user response:
This is one of the several reasons not to use onxyz
-attribute-style event handlers. They can only call global functions, and the global namespace is very crowded and prone to naming conflicts. They also run in a complicated scope that incorporates not only the global environment, but also all of the properties and methods on the element the onxyz
attribute is on and (in some cases) various parents of it. That's what's happening to you: You're running into a situation where claer
exists in that special scope because it exists on the element or its parent(s).
Instead, use addEventListener
. It lets you use non-globals, and reliably attaches the precise function you give it. For instance, to do that with minimal changes to what you have:
let result = document.getElementById("result");
for (const id of ["seven", "eight", "nine"]) {
document.getElementById(id).addEventListener("click", output);
}
document.getElementById("AC").addEventListener("click", clear);
function output() {
result.innerHTML = result.innerHTML event.target.innerHTML;
} // <== Side note: No `;` here, this is a function *declration*
function clear() {
result.innerHTML = "";
} // <== Same
Live Example:
let result = document.getElementById("result");
for (const id of ["seven", "eight", "nine"]) {
document.getElementById(id).addEventListener("click", output);
}
document.getElementById("AC").addEventListener("click", clear);
function output() {
result.innerHTML = result.innerHTML event.target.innerHTML;
}
function clear() {
result.innerHTML = "";
}
<table>
<tr><td colspan="5" id="result" height="40"></td></tr>
<tr>
<td id="seven" >7</td>
<td id="eight" >8</td>
<td id="nine" >9</td>
<td id="C" >C</td>
<td id="AC">AC</td>
</tr>
</table>
(In modern coding, you'd probably have that in a module rather than a script, so that it isn't at global scope.)
But, ideally we wouldn't have to give each and every element an id
like that and refer to them specifically. We could, for instance, use the number
class you have on the digits:
for (const element of document.querySelectorAll(".number") {
element.addEventListener("click", output);
}
document.getElementById("AC").addEventListener("click", clear);
Live Example:
let result = document.getElementById("result");
for (const element of document.querySelectorAll(".number") {
element.addEventListener("click", output);
}
document.getElementById("AC").addEventListener("click", clear);
function output() {
result.innerHTML = result.innerHTML event.target.innerHTML;
}
function clear() {
result.innerHTML = "";
}
<table>
<tr><td colspan="5" id="result" height="40"></td></tr>
<tr>
<td >7</td>
<td >8</td>
<td >9</td>
<td id="C" >C</td>
<td id="AC">AC</td>
</tr>
</table>
CodePudding user response:
Just change the clear function name that will work
let result = document.getElementById("result");
function output() {
result.innerHTML = result.innerHTML event.target.innerHTML;
}
function clearResult() {
document.getElementById("result").innerHTML = "";
}
CodePudding user response:
The problem is "clear()" function already used by other thing, so you cannot use it, the fastest way to solve your problem is by changing the function name only. You could check my answer for this.
Other way to avoid it is actually just to wrap the function inside other thing, as you said you're still learning, so might as well show you the possibility. You could check this on my 2nd example.
let result = document.getElementById("result");
function calcOutput() {
result.innerHTML = result.innerHTML event.target.innerHTML;
};
function calcClear() {
result.innerHTML = "";
};
// For Second Example
const calculator = {
output : () => {
result.innerHTML = result.innerHTML event.target.innerHTML;
},
clear : () => {
result.innerHTML = "";
}
};
<!-- First Example -->
<table>
<tbody>
<tr><td colspan="5" id="result" height="40"></td></tr>
<tr>
<td id="seven" onclick = "calcOutput()">7</td>
<td id="eight" onclick = "calcOutput()">8</td>
<td id="nine" onclick = "calcOutput()">9</td>
<td id="C" >C</td>
<td id="AC" onclick = "calcClear()">AC</td>
</tr>
</tbody>
</table>
<!-- Second Example -->
<table>
<tbody>
<tr><td colspan="5" id="result2nd" height="40"></td></tr>
<tr>
<td id="seven2nd" onclick = "calculator.output()">7</td>
<td id="eight2nd" onclick = "calculator.output()">8</td>
<td id="nine2nd" onclick = "calculator.output()">9</td>
<td id="C2nd" >C</td>
<td id="AC2nd" onclick = "calculator.clear()">AC</td>
</tr>
</tbody>
</table>