Reputation: 305
I'm working on an engine that creates maps files for a game I made. The game is a text based adventure that uses a grid of spaces to display events like messages, items, quests, enemies etc.
The form I'm working on now will create a grid using buttons as the values are type into the input fields - this creates a better visual representation.
I'm working on this function that does the following.
checks if a height has been specified - this way it knows if its drawing a linear room or a rectangular room before anything else is execute
if it's a linear room (only width has been specified), it uses the width to create and append buttons to the containing element.
if it is rectangular (width and height have been specified), a nested for loop runs which appends x amount of buttons for the width, then y amount of
's for the height.
when one of these buttons is clicked, it appends another form to the screen. which can then be filled out by the user.
Here is the code for this:
var creategridwidth = function(room)
{
//store the room in a local variable
var room = room;
//while the grid container has children in it
while(room.subGridContainer.hasChildNodes())
{
//remove the children from the container
room.subGridContainer.removeChild(room.subGridContainer.lastChild);
}
//if the room height has already been set
if(room.heightValue > 0)
{
//loop through the amount of rows
for(var x = 0; x < room.heightValue; x ++)
{
//loop through the amount of columns
for(var y = 0; y < room.widthValue; y ++)
{
//create a new button element
var button = document.createElement('button')
//assign the button element to the grid class
button.setAttribute("class", "grid");
//add an event listener for on click to view input information
button.addEventListener('click', function()
{
console.log("click")
//run add space input function to add the html form to the page.
addspaceinput(room);
}, false);
//display the button as inline block so that they are side by side
button.style.display = "inline-block";
//append the button to the grid container
room.subGridContainer.appendChild(button);
}
//when the row has been added, add a line break to start the next lie.
room.subGridContainer.innerHTML += "<br>";
}
//if the height has not already been set
} else {
//loop through the width of the room
for(var z = 0; z < room.widthValue; z ++)
{
//create a new button element
var button = document.createElement('button')
//assign the button element to the grid class
button.setAttribute("class", "grid");
//add an event listener for on click to view input information
button.addEventListener('click', function()
{
console.log("click")
//run add space input function to add the html form to the page.
addspaceinput(room);
}, false);
//display the button as inline block so that they are side by side
button.style.display = "inline-block";
//append the button to the grid container
room.subGridContainer.appendChild(button);
}
}
}
Now, the part I'm having trouble with is the event listener happening in the nest for loop.
For example:
for(var z = 0; z < room.widthValue; z ++)
{
//create a new button element
var button = document.createElement('button')
//assign the button element to the grid class
button.setAttribute("class", "grid");
//add an event listener for on click to view input information
button.addEventListener('click', function()
{
console.log("click")
//run add space input function to add the html form to the page.
addspaceinput(room);
}, false);
//display the button as inline block so that they are side by side
button.style.display = "inline-block";
//append the button to the grid container
room.subGridContainer.appendChild(button);
}
I can see this log appear in the console, this works fine. However:
for(var x = 0; x < room.heightValue; x ++)
{
//loop through the amount of columns
for(var y = 0; y < room.widthValue; y ++)
{
//create a new button element
var button = document.createElement('button')
//assign the button element to the grid class
button.setAttribute("class", "grid");
//add an event listener for on click to view input information
button.addEventListener('click', function()
{
console.log("click")
//run add space input function to add the html form to the page.
addspaceinput(room);
}, false);
//display the button as inline block so that they are side by side
button.style.display = "inline-block";
//append the button to the grid container
room.subGridContainer.appendChild(button);
}
//when the row has been added, add a line break to start the next lie.
room.subGridContainer.innerHTML += "<br>";
}
This gives absolutely no behavior. I'm not sure how to move forward with this. I'd appreciate any suggestions on this.
Upvotes: 1
Views: 290
Reputation: 370689
The problem is here:
room.subGridContainer.innerHTML += "<br>";
When you assign to innerHTML
, the existing innerHTML
is retrieved, the element is cleared, and then the new concatenated innerHTML
string is parsed into the DOM. So, any variables referencing elements inside will be lost, including elements that used to have event listeners.
const button = document.body.appendChild(document.createElement('button'));
button.textContent = 'click';
button.onclick = () => console.log('clicked');
// the next line will break the listener:
document.body.innerHTML += '<br>';
Explicitly append elements instead:
room.subGridContainer.appendChild(document.createElement('br'));
Another option would be to insertAdjacentHTML
:
room.subGridContainer.insertAdjacentHTML('beforeend', '<br>');
But if you want the button to be on its own line, it would be better to put it inside a block element, rather than append br
s:
var div = room.subGridContainer.appendChild(document.createElement('div'));
var button = div.appendChild(document.createElement('button'));
// etc
Upvotes: 1