Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Javascript, addEventListener not working

Hey guys! I have made a table, with 10 tr's each having 10 td's. This is layed out as a grid that 10 x 10. I have added a class="table2" to each of the tds, and ids ranging from 0 - 99.

Im trying to addEventListener to each of the individual td's. My code looks like this:

let mark2 = document.querySelectorAll(".table2");
for (let i = 0; i <= 99; i++) {
    mark2[i].addEventListener("click", function clicked3() {
        mark2[this.id].style.backgroundColor = "black";
    });
};

So basicly im trying to make it so that if you click the a td, that specific td will turn black. However when i run this, im getting the error: Uncaught TypeError: Cannot read property 'addEventListener' of undefined.

I dont get this, i defined it just above? Help would be greatly appreciated!

Ok so something seriously strange is going on here. Below ill link both my html and javascript document: HTML:

<!DOCTYPE html>
<html>
<head>
<title>Testing</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
    <h1>Bresenhams line drawing algorithm visualised!</h1>
    <p>Two random points will be sellected on the screen. The first point in <span id="span1">red </span>and the second point in <span id="span2">blue</span>.You will have to try to connect them as good as you can. Once your done simply press the button at the bottom of the page, and it will show you how bresenham would of done it!</p>
    <table>
        <tr>
            <td class="table" id="0"></td>
            <td class="table" id="1"></td>
            <td class="table" id="2"></td>
            <td class="table" id="3"></td>
            <td class="table" id="4"></td>
            <td class="table" id="5"></td>
            <td class="table" id="6"></td>
            <td class="table" id="7"></td>
            <td class="table" id="8"></td>
            <td class="table" id="9"></td>
        </tr>
        <tr>
            <td class="table" id="10"></td>
            <td class="table" id="11"></td>
            <td class="table" id="12"></td>
            <td class="table" id="13"></td>
            <td class="table" id="14"></td>
            <td class="table" id="15"></td>
            <td class="table" id="16"></td>
            <td class="table" id="17"></td>
            <td class="table" id="18"></td>
            <td class="table" id="19"></td>
        </tr>
        <tr>
            <td class="table" id="20"></td>
            <td class="table" id="21"></td>
            <td class="table" id="22"></td>
            <td class="table" id="23"></td>
            <td class="table" id="24"></td>
            <td class="table" id="25"></td>
            <td class="table" id="26"></td>
            <td class="table" id="27"></td>
            <td class="table" id="28"></td>
            <td class="table" id="29"></td>
        </tr>
        <tr>
            <td class="table" id="30"></td>
            <td class="table" id="31"></td>
            <td class="table" id="32"></td>
            <td class="table" id="33"></td>
            <td class="table" id="34"></td>
            <td class="table" id="35"></td>
            <td class="table" id="36"></td>
            <td class="table" id="37"></td>
            <td class="table" id="38"></td>
            <td class="table" id="39"></td>
        </tr>
        <tr>
            <td class="table" id="40"></td>
            <td class="table" id="41"></td>
            <td class="table" id="42"></td>
            <td class="table" id="43"></td>
            <td class="table" id="44"></td>
            <td class="table" id="45"></td>
            <td class="table" id="46"></td>
            <td class="table" id="47"></td>
            <td class="table" id="48"></td>
            <td class="table" id="49"></td>
        </tr>
        <tr>
            <td class="table" id="50"></td>
            <td class="table" id="51"></td>
            <td class="table" id="52"></td>
            <td class="table" id="53"></td>
            <td class="table" id="54"></td>
            <td class="table" id="55"></td>
            <td class="table" id="56"></td>
            <td class="table" id="57"></td>
            <td class="table" id="58"></td>
            <td class="table" id="59"></td>
        </tr>
        <tr>
            <td class="table" id="60"></td>
            <td class="table" id="61"></td>
            <td class="table" id="62"></td>
            <td class="table" id="63"></td>
            <td class="table" id="64"></td>
            <td class="table" id="65"></td>
            <td class="table" id="66"></td>
            <td class="table" id="67"></td>
            <td class="table" id="68"></td>
            <td class="table" id="69"></td>
        </tr>
        <tr>
            <td class="table" id="70"></td>
            <td class="table" id="71"></td>
            <td class="table" id="72"></td>
            <td class="table" id="73"></td>
            <td class="table" id="74"></td>
            <td class="table" id="75"></td>
            <td class="table" id="76"></td>
            <td class="table" id="77"></td>
            <td class="table" id="78"></td>
            <td class="table" id="79"></td>
        </tr>
        <tr>
            <td class="table" id="80"></td>
            <td class="table" id="81"></td>
            <td class="table" id="82"></td>
            <td class="table" id="83"></td>
            <td class="table" id="84"></td>
            <td class="table" id="85"></td>
            <td class="table" id="86"></td>
            <td class="table" id="87"></td>
            <td class="table" id="88"></td>
            <td class="table" id="89"></td>
        </tr>
        <tr>
            <td class="table" id="90"></td>
            <td class="table" id="91"></td>
            <td class="table" id="92"></td>
            <td class="table" id="93"></td>
            <td class="table" id="94"></td>
            <td class="table" id="95"></td>
            <td class="table" id="96"></td>
            <td class="table" id="97"></td>
            <td class="table" id="98"></td>
            <td class="table" id="99"></td>
        </tr>
    </table>
    <button id="bresenham">See solution</button><button id="reset">Reset</button>
    <script src="Javascript.js"></script>
    <p id="paragraph">Here you can sellect two points on the grid bellow and it will draw a line between those two points</p>
    <table>
        <tr>
            <td class="table2" id="a0"></td>
            <td class="table2" id="a1"></td>
            <td class="table2" id="a2"></td>
            <td class="table2" id="a3"></td>
            <td class="table2" id="a4"></td>
            <td class="table2" id="a5"></td>
            <td class="table2" id="a6"></td>
            <td class="table2" id="a7"></td>
            <td class="table2" id="a8"></td>
            <td class="table2" id="a9"></td>
        </tr>
        <tr>
            <td class="table2" id="a10"></td>
            <td class="table2" id="a11"></td>
            <td class="table2" id="a12"></td>
            <td class="table2" id="a13"></td>
            <td class="table2" id="a14"></td>
            <td class="table2" id="a15"></td>
            <td class="table2" id="a16"></td>
            <td class="table2" id="a17"></td>
            <td class="table2" id="a18"></td>
            <td class="table2" id="a19"></td>
        </tr>
        <tr>
            <td class="table2" id="a20"></td>
            <td class="table2" id="a21"></td>
            <td class="table2" id="a22"></td>
            <td class="table2" id="a23"></td>
            <td class="table2" id="a24"></td>
            <td class="table2" id="a25"></td>
            <td class="table2" id="a26"></td>
            <td class="table2" id="a27"></td>
            <td class="table2" id="a28"></td>
            <td class="table2" id="a29"></td>
        </tr>
        <tr>
            <td class="table2" id="a30"></td>
            <td class="table2" id="a31"></td>
            <td class="table2" id="a32"></td>
            <td class="table2" id="a33"></td>
            <td class="table2" id="a34"></td>
            <td class="table2" id="a35"></td>
            <td class="table2" id="a36"></td>
            <td class="table2" id="a37"></td>
            <td class="table2" id="a38"></td>
            <td class="table2" id="a39"></td>
        </tr>
        <tr>
            <td class="table2" id="a40"></td>
            <td class="table2" id="a41"></td>
            <td class="table2" id="a42"></td>
            <td class="table2" id="a43"></td>
            <td class="table2" id="a44"></td>
            <td class="table2" id="a45"></td>
            <td class="table2" id="a46"></td>
            <td class="table2" id="a47"></td>
            <td class="table2" id="a48"></td>
            <td class="table2" id="a49"></td>
        </tr>
        <tr>
            <td class="table2" id="a50"></td>
            <td class="table2" id="a51"></td>
            <td class="table2" id="a52"></td>
            <td class="table2" id="a53"></td>
            <td class="table2" id="a54"></td>
            <td class="table2" id="a55"></td>
            <td class="table2" id="a56"></td>
            <td class="table2" id="a57"></td>
            <td class="table2" id="a58"></td>
            <td class="table2" id="a59"></td>
        </tr>
        <tr>
            <td class="table2" id="a60"></td>
            <td class="table2" id="a61"></td>
            <td class="table2" id="a62"></td>
            <td class="table2" id="a63"></td>
            <td class="table2" id="a64"></td>
            <td class="table2" id="a65"></td>
            <td class="table2" id="a66"></td>
            <td class="table2" id="a67"></td>
            <td class="table2" id="a68"></td>
            <td class="table2" id="a69"></td>
        </tr>
        <tr>
            <td class="table2" id="a70"></td>
            <td class="table2" id="a71"></td>
            <td class="table2" id="a72"></td>
            <td class="table2" id="a73"></td>
            <td class="table2" id="a74"></td>
            <td class="table2" id="a75"></td>
            <td class="table2" id="a76"></td>
            <td class="table2" id="a77"></td>
            <td class="table2" id="a78"></td>
            <td class="table2" id="a79"></td>
        </tr>
        <tr>
            <td class="table2" id="a80"></td>
            <td class="table2" id="a81"></td>
            <td class="table2" id="a82"></td>
            <td class="table2" id="a83"></td>
            <td class="table2" id="a84"></td>
            <td class="table2" id="a85"></td>
            <td class="table2" id="a86"></td>
            <td class="table2" id="a87"></td>
            <td class="table2" id="a88"></td>
            <td class="table2" id="a89"></td>
        </tr>
        <tr>
            <td class="table2" id="a90"></td>
            <td class="table2" id="a91"></td>
            <td class="table2" id="a92"></td>
            <td class="table2" id="a93"></td>
            <td class="table2" id="a94"></td>
            <td class="table2" id="a95"></td>
            <td class="table2" id="a96"></td>
            <td class="table2" id="a97"></td>
            <td class="table2" id="a98"></td>
            <td class="table2" id="a99"></td>
        </tr>
    </table>
</body>
</html>

JAVASCRIPT:

// Sellect the table
let mark = document.querySelectorAll(".table"); // THIS DOES WORK ??????????
let test = document.querySelectorAll(".table2"); // THIS DOES NOT WORK ???????
// Add an event listener to all td's and set background to black if clicked
for (let i = 0; i <= 99; i++) {
    mark[i].addEventListener("click", function clicked() {
        mark[this.id].style.backgroundColor = "black";
    });
};
sellectTwoPoints();
// Ádd event listener to reset and make it reset
let reset = document.getElementById("reset");
reset.addEventListener("click", function test() {
    for (let i = 0; i <= 99; i++) {
        mark[i].style.backgroundColor = "white";
    }
    console.clear();
    sellectTwoPoints();
});

// Make function to sellect two random points and mark them red and blue
function sellectTwoPoints() {
    first_point = Math.floor((Math.random() * 100) + 1);
    second_point = Math.floor((Math.random() * 100) + 1);
    mark[first_point].style.backgroundColor = "red";
    mark[second_point].style.backgroundColor = "blue";
    cords();
};
// Ensure two random poitns arent the same
if (first_point === second_point) {
    sellectTwoPoints();
};
// Sellect the button to initiate bresenham
const bresenham = document.getElementById("bresenham")
// Add event listener to button
bresenham.addEventListener("click", function clicked2() {
    array = drawLine(x1, y1, x2, y2);
    for (let i = 0; i < array.length; i++)
    ids(array[i])
});
// Figure out x and y cords based on the ids
function cords() {
    y1 = 10 - Math.floor(first_point / 10);
    y2 = 10 - Math.floor(second_point / 10);
    x1 = Math.round(((first_point / 10) % 1) * 10 + 1);
    x2 = Math.round(((second_point / 10) % 1) * 10 + 1);
    console.log("y1 = " + y1);
    console.log("y2 = " + y2);
    console.log("x1 = " + x1);
    console.log("x2 = " + x2);
}
// Figure out ids based on x and y and make color green
function ids([x_value, y_value]) {
    id = 99 - y_value * 10 + x_value;
    mark[id].style.backgroundColor = "green"
}
// Create a function for the line algorithm
function drawLine(x_1, y_1, x_2, y_2) {
    // Setup initial constants
    dy = y_2 - y_1;
    dx = x_2 - x_1;
    // Figure how how steep line is
    is_steep = Math.abs(dy) > Math.abs(dx);
    // Switch if the line is steep
    if (is_steep) {
        x_1 = [y_1, y_1 = x_1][0];
        x_2 = [y_2, y_2 = x_2][0]; //These may be flored
    }
    // Swap start and end points if necessary and store swap state
    swapped = false;
    if (x_1 > x_2) {
        x_1 = [x_2, x_2 = x_1][0];
        y_1 = [y_2, y_2 = y_1][0]; //These may be flored
        swapped = true;
    }
    // Recalculate initial constants
    dx = x_2 - x_1;
    dy = y_2 - y_1;
    // Calculate error
    error = parseInt(dx / 2.0);
    if (y_1 < y_2) {
        ystep = 1;
    } else {
        ystep = -1;
    }
    // Iterate over bounding box generating points between start and end
    y = y_1;
    x1_loop = x_1;
    points = [];
    for (let i = x1_loop; x1_loop < x_2 + 1; x1_loop++) {
        if (is_steep) {
            coord = [y, i];
        } else {
            coord = [i, y];
        }
        i = i + 1 // Test
        points.push(coord);
        error -= Math.abs(dy);
        if (error < 0) {
            y += ystep;
            error += dx;
        }
    }
    // Reverse points if swapped
    if (swapped) {
        points.reverse();
    }
    // Log points to console and color all the ids
    console.log("points = " + points);
    return points;
}
// Add event listener to grid 2

So at the very top of the javascript document i am sellecting both the td's with the class .table and .table2... table works just as it should, but .table2 has some weiiird behaviour. If you open the developer tools and you write mark[0], it will return: <td class="table" id="0"></td>, as excpected. However do the same for test, and it will return: undefined. This makes no sense to me

1 Answer

Steven Parker
Steven Parker
230,958 Points

The id values in table2 are not numbers. They are all strings beginning with the letter "a" followed by a number.

So instead of "mark2[this.id]", you need something like "mark2[parseInt(this.id.slice(1))]".

Thx for the response steven, im not sure i understand tho. I tried just replacing it with your code:

let mark2 = document.querySelectorAll(".table2");
for (let i = 0; i <= 99; i++) {
    mark2[i].addEventListener("click", function clicked() {
        mark2[parseInt(this.id.slice(1))].style.backgroundColor = "black";
    });
};

This returns: Uncaught TypeError: Cannot read property 'addEventListener' of undefined at Javascript.js:114. So still the same issue. And also i dont think thats the only issue, because even if you simply try to sellect the .table2 class, something will go wrong, it wont be sellected correctly.

Steven Parker
Steven Parker
230,958 Points

Odd, that same exact code works for me. Could something have changed in the HTML?

Well no, i have not changed anything in the html what so ever. (Took an in depth look just now, and copy pasted what i posted above). The code does not work, have you tried to actually copy paste both the html and js file and launched it, because i think that when the issue will occour?

Could it have anything to do with the fact that i used global variables?

Steven Parker
Steven Parker
230,958 Points

When I use that script code with the HTML from above, I can click on the cells of the 2nd table and they turn black.

Is this in a workspace where you share the entire thing in a snapshot?

I didnt create this in a workspace, i made it on my local machine. But i wanted to show you it didnt work, and so i created i workspace, made 3 files, for html css and js, names them exacly the same, and then copy pasted the code. And it works in the worksspace?? This makes no sense what so ever. The code at this point dosent even throw an error it just does not respond to clicks. I can include some screenshots, but im not sure if they would be usefull at all

Steven Parker
Steven Parker
230,958 Points

Screenshots are not very useful, but a snapshot would allow me to replicate your exact environment and try it out.

Riight so this is rather embarrising. Apperently when i moved the files into another folder it automaticly created a copy of the .js file in the original folder. This was ofcourse the file that i had open in sublime text, but the index.html was linked to the .js file in the new folder.. So basicly from the point that it threw an error, i was implementing all of these changes in the .js file that was not linked to the index.html, which is why it kept giving me the same error, and why it worked im the worksspace... So sorry for wasting your time Steven, but thanks for the code you originally provided, it works perfectly now!