Encountering difficulties in targeting a JavaScript generated button within an array using a function, resulting in an error message that reads "Unable to read property 'setAttribute' of null"

Trying to change the background of a specific button when clicking on it is proving to be quite the challenge for me. I created an array of 100 buttons (with the intention of developing a simple game later) using a for loop, giving each button a unique id and function call based on the 'i' value incrementing in the loop. However, I am encountering an error instead of successfully changing the background upon clicking, which reads: "Uncaught TypeError: Cannot read property 'setAttribute' of null at showOptions (brain.js:31) at HTMLButtonElement.onclick (index.html:15)"

The code snippet looks something like this:

var btn = [];
function generateBoard() {
  for (i = 0; i < 100; i++) {
    var modulo = i % 10;
    var up, forLeft;
    btn[i] = document.createElement("BUTTON");
    var element = document.getElementById("body");
    //btn[i].innerText = "CLICK ME";
    element.appendChild(btn[i]);
    btn[i].style.backgroundColor = "white";
    btn[i].id = i;
    btn[i].style.width = "50px";
    btn[i].style.height = "40px";
    btn[i].style.position = "absolute";
    btn[i].style.top = modulo * 100;
    btn[i].style.left = Math.floor(i / 10) * 100;
    btn[i].x = (i + 10) % 10;
    btn[i].y = Math.floor(i / 10);
    document
      .getElementById(btn[i].id)
      .setAttribute("onclick", "showOptions(i)");
    btn[i].innerText = btn[i].id;

    console.log(
      btn[i].id +
        " " +
        btn[i].style.left +
        " " +
        btn[i].style.top +
        " " +
        btn[i].x +
        " " +
        btn[i].y
    );
  }
}
generateBoard();
function showOptions(i) {
  document.getElementById(i).setAttribute("style", "background-color: red;"); //this is line 31
}

In the console log, I can see that btn[i].id shows the correct digit, surprisingly.

The error line (index.html:15) simply points to

</html>

Answer №1

Your code has a few issues that need attention.
To access the body element, use getElementsByTagName, which returns an array. Therefore, you should select the first element from this array.
When setting the onclick attribute, make sure to use the value of i instead of the text i.

var btn = [];

function generateBoard() {
  for (i = 0; i < 100; i++) {
    var modulo = i % 10;
    var up, forLeft;
    btn[i] = document.createElement("BUTTON");
    var element = document.getElementsByTagName("body")[0];
    //btn[i].innerText = "CLICK ME"; 
    element.appendChild(btn[i]);
    btn[i].style.backgroundColor = "white";
    btn[i].id = i;
    btn[i].style.width = "50px";
    btn[i].style.height = "40px";
    btn[i].style.position = "absolute";
    btn[i].style.top = modulo * 100;
    btn[i].style.left = Math.floor(i / 10) * 100;
    btn[i].x = (i + 10) % 10;
    btn[i].y = Math.floor(i / 10);
    
    document.getElementById(btn[i].id).setAttribute('onclick', 'showOptions(' + i + ')');
    btn[i].innerText = btn[i].id;


    console.log(btn[i].id + " " + btn[i].style.left + " " + btn[i].style.top + " " + btn[i].x + " " + btn[i].y);

  }
}
generateBoard();

function showOptions(i) {

  document.getElementById(i).setAttribute("style", "background-color: red;"); //this is line 31
}

Answer №2

I have revised your code to address certain issues. It is assumed that you possess an element tagged with the id body, which is different from the actual body element accessible via document.body.

var buttons = [];

function generateBoard(){
    for(i = 0; i < 100; i++) {
        var remainder = i % 10;
        buttons[i] = document.createElement("BUTTON");
        document.getElementById("body").appendChild(buttons[i]);
        
        buttons[i].style.backgroundColor = "white";
        buttons[i].id = i;
        buttons[i].style.width = "50px";
        buttons[i].style.height = "40px";
        buttons[i].style.position = "absolute";
        buttons[i].style.top = remainder * 100;
        buttons[i].style.left = Math.floor(i / 10) * 100;
        buttons[i].x = (i + 10) % 10;
        buttons[i].y = Math.floor(i / 10);
        buttons[i].addEventListener('click', function(event) {
            showOptions(this);
        });
        buttons[i].innerText = i;

        console.log(buttons[i].id + " " + buttons[i].style.left + " " + buttons[i].style.top + " " + buttons[i].x + " " + buttons[i].y);
    }
}
generateBoard();

function showOptions(button){
    button.style.backgroundColor = "red";
}

Answer №3

Instead of assigning and trying to utilize an ID attribute, you can target the clicked element by referencing a property of the event itself. By inspecting the event (using console), you will notice various properties - the target provides access to the element itself, simplifying the showOptions function. Alternatively, you could simply use this within showOptions to directly refer to the button itself, making it even easier, like

this.style.backgroundColor='red';

let buttons=[];

const createBoard=function( size=100 ){
  const showOptions=function(e){
    e.target.style.backgroundColor='red';
  };

  for( let i=0; i < size; i++ ){
    /* create a new button and set attributes */
    let button=document.createElement('button');
      button.setAttribute('id',i);
      button.setAttribute('data-x',((i+10)%10));
      button.setAttribute('data-y',Math.floor(i/10));

      button.style.left=( Math.floor( i / 10 ) * 100 )+'px';
      button.style.top=( ( i % 10 ) * 100 )+'px';
      button.style.width = '50px';
      button.style.height = '40px';
      button.style.position = 'absolute';
      button.innerText=i;

      /* bind event listener */
      button.addEventListener('click', showOptions );

    /* add to the DOM */
    document.body.appendChild( button );

    /* store in array if needed */
    buttons.push( button );
  }
}

document.addEventListener('DOMContentLoaded',(e)=>{
  createBoard( 100 );
})

It is not recommended to add random attributes to elements - rather than using x and y, utilizing dataset attributes such as data-x and data-y is considered best practice.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What could be causing the icon link to not show up in Bootstrap 4?

Currently, I am engrossed in reading the book titled "ASP .NET MVC 5." However, I have hit a roadblock. The author utilizes Bootstrap 3 in the book, but the newer version of Bootstrap contains some modifications that are causing me difficulties in solving ...

The AJAX functionality seems to have broken following the switch from php5 to php7

When I initially wrote my code in php5, the index page would make an ajax call to check if $_SESSION['user'] was stored. If a session existed, the user's information would be displayed; otherwise, the page would redirect to the login page. H ...

The navigation bar's HTML hue

Currently working on a website design and looking to replicate the unique color gradient effect seen in the top navigation bar of Virgin America airlines' website (refer to the image linked below). Interested in any CSS/HTML techniques that could help ...

Strategies for transferring information to a different component in a React application

Building a movie site where users can search for films, click on a card, and access more details about the film is proving challenging. The problem lies in transferring the film details to the dedicated details page once the user clicks on the card. An onc ...

Implementing object rotation towards a target using three.js

Even though I have been working with vector graphics for over 13 years now, I still find it challenging to grasp how three.js handles things. One thing I am trying to achieve is having an object that always faces the camera and rotates accordingly. In ano ...

the power of using keywords and prototypes

Greetings! I am currently delving into the realm of JavaScript, hailing from a C++ background. The transition has proven to be quite perplexing for me. Below is a snippet of code that I have been troubleshooting: var someArray = []; nameCompare = function ...

In Android Kitkat 4.4.4, the Ionic navbar displays icons vertically when using the <ion-buttons end> feature

When viewing in the browser with ionic serve, everything looks fine. However, on an Android Kitkat device running version 4.4.4, the buttons on the right side of the navbar are displaying vertically instead of horizontally. <ion-navbar> <ion-ti ...

Implementing a class for a dropdown menu within a JavaScript function

I recently came across a code that I am interested in using on my form to automatically select an option when clicking on a div. $("div").on("click", function(e) { var $select = $("select"); $select.val($(this).data("value")); // simulate cli ...

Steps for creating a clickable product item card throughout

I am looking to modify my Product Card design. Currently, there is a hyperlink named Buy at the end of the card that users can click on. However, I want to make the entire card clickable with another hyperlink so users do not have to specifically click on ...

Utilizing the onCLICK event handler with numerous parameters

I'm in need of assistance with creating a function that involves multiple variables, preferably at least two... The table I am working with was generated using PHP and MySQL, all IDs were dynamically created which is why I am looking for a way to cap ...

What methods are available to apply a class to an element in an array when hovering over it?

Is there a way to add a class to an element when hovering over it in an array of elements? ...

How to optimize updating object properties with setState?

Is there a more efficient way to rewrite this code? For example, would using setState(ContentStore.getAll()) achieve the same outcome? I believe this approach appears overly cluttered and any method to simplify the code for readability would be greatly app ...

Switch between list items using a button to change the ID in Javascript

I am trying to implement a floating navbar that appears after a button click and floats down from the top. The idea is that when the button is clicked, the navbar animates downward and then changes the button's id so that the next click triggers a dif ...

Passing HTML element values to Python in Odoo 10: A complete guide

I am working on an Odoo module that includes an Html <select> tag. I need to pass the value of the <option> (within the select tag) to a Python model so that I can perform certain actions based on this value. Can anyone provide guidance on how ...

Retrieve the child elements of several tags using selenium

Is there a way to retrieve all sub elements of multiple elements that share the same class? <html> <body> <h3 class="searchresult"> <a href='/lorem1'>Text1</a> </h3> <h3 class="searchresult ...

I am experiencing a problem where my webpage does not load properly when trying to access it

After setting up a route triggered by a specific click event using AJAX, I noticed that although my route is being called, the page content is not rendered as expected. Here is my AJAX function: function showProfile(user_id) { console.log("show pro:" + u ...

Trying to set headers in Node/Express after they have already been sent is causing an error

I am attempting to send form data from the client side using jQuery to a POST route that will then pass the data to an API in Node/Express. I am encountering an issue where I receive the error message "Can't set headers after they are sent" and I am ...

What is the best way to send parameters to a callback function in a jQuery $.getJSON method?

Currently, I am attempting to utilize jQuery to access a custom API using Ajax/$.getJSON. In my code, I am trying to send a specific value to the Ajax callback method, but I am encountering an issue where this value is not being properly passed and instea ...

Retrieve the unique identifier of the dynamically created button

I have been struggling to retrieve the ID of a dynamically generated button. I attempted to access the specific button ID and utilize it for beforeSend:function(id). However, my efforts were not fruitful. <?php session_start(); require_once "../aut ...

Issue with Bootstrap 4's vertical alignment center in flex layout not functioning as expected

Im using Bootstrap 4 to create a responsive layout with 3 columns that adjust order, width, and horizontal alignment based on screen size. Everything is functioning correctly except for the horizontal center alignment of the images on screens smaller than ...