Reputation:
I'm trying to learn Web Development with Javascript and HTML. My problem is that I'm trying to implement a for loop (2nd method) that do some logic instead of the redudant code (1st method) but I can't seem to get method 2 working. Please see if there is any other mistake in method 2, I rlly don't like the fact typing the id for each button over and over again. Let me know how I can fix or improve method 2, thanks a lot!
UPDATED
<div id="num">
<tr>
<td>
<input type="button" value="1">
<input type="button" value="2">
<input type="button" value="3">
<input type="button" value="+">
</td>
</tr>
<br>
<tr>
<td>
<input type="button" value="4">
<input type="button" value="5">
<input type="button" value="6">
<input type="button" value="-">
</td>
</tr>
<br>
<tr>
<td>
<input type="button" value="7">
<input type="button" value="8">
<input type="button" value="9">
<input type="button" value="*">
</td>
</tr>
<br>
<tr>
<td>
<input type="button" value="/">
<input type="button" value="0">
<input type="reset" value="Reset">
</td>
</tr>
</div>
<br>
<input type="button" value="=" onClick="document.calculator.ans.value=eval(document.calculator.ans.value)">
<br>Solution is <input type="textfield" name="ans" value="">
</form>
<script>
const num = document.getElementById("num");
const length = num.length;
obj.onclick = function()
{
for (let i = 1; i < length; i++)
{
num.addEventListener("click")
}
}
</script></strike>
Upvotes: 0
Views: 206
Reputation: 49632
You do not need to create one event listener for every button. It is enough to use ONE on an element that somewhere contains the buttons.
This is an example of how I would start to do what you are trying to do.
function handle(event) {
// The clicked element is in event.target
const button = event.target;
// using the name of the clicked element to determine what to do.
if (button.name === "digit") {
const value = Number(button.value);
console.log("Digit %d was pressed", value);
}
else if (button.name === "op") {
switch(button.value) {
case "+":{
console.log("Operator +");
break;
}
case "-":{
console.log("Operator -");
break;
}
}
}
}
const pad = document.getElementById("pad");
pad.addEventListener("click", handle); // Attach ONE click-handler
<div id="pad">
<button name="digit" value="1">1</button>
<button name="digit" value="2">2</button>
<button name="digit" value="3">3</button>
<div>
<div>
<div>
<div>
<!--
The don't have to be direct chilren.
As long as they are somewhere inside the
div that have the event-handler the event
handler will see them.
-->
<button name="op" value="+">+</button>
<button name="op" value="-">-</button>
</div>
</div>
</div>
</div>
</div>
UPDATE
You requested in a comment a way to use for-loops instead. Here is an example: I'm using querySelectorAll to get all the elements and then for...of to iterate over the array-like result.
The key here is to give all the buttons that have the same meaning something that can be selected. In my example I have set the name-attribute/property on all buttons, "digit" for digits, and "op" for operators, and then use the value-attribute/property to know what the button is supposed to do.
for (const elem of document.querySelectorAll("button[name=digit]")){
console.log("Digit", elem.value);
}
for (const elem of document.querySelectorAll("button[name=op]")){
console.log("Operator", elem.value);
}
// With a low-level for-loop
const elements = document.querySelectorAll("button[name=digit]");
const length = elements.length;
for (let index=0; index < length; index += 1) {
const elem = elements[index];
console.log("Long way to get the value of digit",elem.value);
}
<div id="pad">
<button name="digit" value="1">1</button>
<button name="digit" value="2">2</button>
<button name="digit" value="3">3</button>
<button name="op" value="+">+</button>
<button name="op" value="-">-</button>
</div>
Let us go though your code
obj = document.querySelectorAll("#num");
// You start by asking for all elements with an id of "num".
// querySelectorAll returns a static node list with matching
// elements. An id should be unique in a document. So there should only
// be ONE matching element.
obj.onclick = function()
// here you try to add a click handler to obj. But obj is not an
// element. It is a list of nodes.
{
// this for-loop looks alright....
for (let i = 1; i < obj.length; i++)
{
// But here you are trying to add eventlisteners inside a
// an eventlistener. You don't want to add that on every
// click.
obj[i].addEventListener('click', () => {
// Here you are using getAttribute, but you don't need that.
console.log(obj[i].getAttribute('value'))
// You can access value as a property:
// console.log(obj[i].value)
})
}
}
Looking at your other atempt:
const num = document.getElementById("num");
// Now you are using getElementById, that will give you the
// node of your outer div. That is a good start, but you
// don't get the individual buttons.
const length = num.length;
obj.onclick = function()
{
// you are starting with 1, but javascript is it 0 based.
for (let i = 1; i < length; i++)
{
num.addEventListener("click")
}
}
What you could do (untested, might contain errors):
// Get a static node list of all buttons.
const buttons = document.querySelectorAll("input[type=button]");
const length = buttons.length;
// event handler that will be called when a button i clicked.
function handle(event) {
const value = event.target.value;
switch ( value ) {
case "+" :
console.log("+ was clicked");
break;
default:
console.log("%s was clicked", value);
}
}
// Adding the event handler to the buttons.
for( let i = 0; i < length; i++) {
buttons[i].addEventListener("click", handle);
}
Upvotes: 2
Reputation: 29521
If you want to get all the buttons (#num1
, #num2
, #num3
... etc.) then you need to use the following:
document.querySelectorAll('[id^="num"]');
The CSS selector
[id^="num"]
means:
every element that has an id
attribute, where the id
begins with "num".
N.B. Note that the method .querySelectorAll()
returns a NodeList object which is array-like but not an array.
If you want an array, you can use the spread operator (...
):
[... document.querySelectorAll('[id^="num"]')];
Upvotes: 0