Skip to content
Advertisement

Cannot access element after creating it with append child

I am trying to create a chess game using html and js.

Here is part of my HTML code:

<div id="board">
            <div id="1">
                <p name="a" class="white"><img class="icon" id="rw1" src="icons/rookw.png"></p>
                <p name="b" class="black"><img class="icon" id="nw1" src="icons/knightw.png"></p>
                <p name="c" class="white"><img class="icon" id="bw1" src="icons/bishw.png"></p>
                <p name="d" class="black"><img class="icon" id="qw"  src="icons/queenw.png"></p>
                <p name="e" class="white"><img class="icon" id="kw"  src="icons/kingw.png"></p>
                <p name="f" class="black"><img class="icon" id="bw2" src="icons/bishw.png"></p>
                <p name="g" class="white"><img class="icon" id="nw2" src="icons/knightw.png"></p>
                <p name="h" class="black"><img class="icon" id="rw2" src="icons/rookw.png"> </p>
            </div>
            <div id="2">
                <p name="a" class="black"><img class="icon" id="pwa" src="icons/pawnw.png"></p>
                <p name="b" class="white"><img class="icon" id="pwb" src="icons/pawnw.png"></p>
                <p name="c" class="black"><img class="icon" id="pwc" src="icons/pawnw.png"></p>
                <p name="d" class="white"><img class="icon" id="pwd" src="icons/pawnw.png"></p>
                <p name="e" class="black"><img class="icon" id="pwe" src="icons/pawnw.png"></p>
                <p name="f" class="white"><img class="icon" id="pwf" src="icons/pawnw.png"></p>
                <p name="g" class="black"><img class="icon" id="pwg" src="icons/pawnw.png"></p>
                <p name="h" class="white"><img class="icon" id="pwh" src="icons/pawnw.png"></p>
            </div>
            <div id="3">
                <p name="a" class="white"></p>
                <p name="b" class="black"></p>
                <p name="c" class="white"></p>
                <p name="d" class="black"></p>
                <p name="e" class="white"></p>
                <p name="f" class="black"></p>
                <p name="g" class="white"></p>
                <p name="h" class="black"></p>
..........
</div>

Here is the JS

var selector = "";
var pawns = document.querySelectorAll('img');
for (let pawn of pawns) {
    pawn.onclick = select;
}
function select() {
    if (selector != "") {
        document.getElementById(selector).style.backgroundColor = "transparent";
    }
    selector = this.id;
    document.getElementById(selector).style.backgroundColor = "rgba(75, 137, 78, 0.5)";
}
var squares = Array.from(document.querySelectorAll("p")).filter(item => !item.querySelector(".icon"));
for (let square of squares) {
    square.onclick = move;
}
function move() {
    if (selector == "")
    {
        return;
    }
    console.log("yes");
    var initial_img = document.getElementById(selector);
    var img = document.createElement("img");
    img.src = initial_img.src;
    this.appendChild(img);
    document.getElementById(selector).style.backgroundColor = "transparent";
    selector="";
    console.log(img.nodeName);
    //initial_img.remove(img);
}

Everything works fine but the problem is when I use append child to copy image , I can no longer select the copied image. I can still select original one.

Advertisement

Answer

The problem is that you are appending a new image that does not have onclick event listener, id or a className. So you would have to add those to the new appended image.

But even if you do that there is another problem which is that the image onclick and the onclick of the square that the new image is on will both fire at the same time making the image just move in its place.

To solve both of these problems in a simple way I suggest that you just add the move handler to all the squares and then inside check if the current square has any child nodes. If it does then just return.

function move() {
  if (selector == '' || this.children.length) return
  
  ...
}

And ofcourse you would want later to add more logic if the square is occupied by enemy.

Now for moving the image from one square to another you can simply append the current selected image to the new square and it will be remove from the old one so no need to create new images:

 const initial_img = document.getElementById(selector)
 this.appendChild(initial_img)

Here is a simple runnable example of the suggested fixes. The css and the opacity stuff are just for demo:

let selector = ''
const pawns = document.querySelectorAll('img')
const squares = [...document.querySelectorAll('p')]

for (let pawn of pawns) {
  pawn.onclick = select
}

for (let square of squares) {
  square.onclick = move
}

function select() {
  if (selector != '') {
    document.getElementById(selector).style.opacity = 1
  }
  selector = this.id
  document.getElementById(selector).style.opacity = 0.5
}

function move() {
  // If nothing is selected or if the current cell
  // is occupied (its children length is not zero)
  // then just return
  if (selector == '' || this.children.length) return

  // Get the selected image and append it to the new
  // square. This will remove the image from the previous
  // square.
  const initial_img = document.getElementById(selector)
  this.appendChild(initial_img)

  document.getElementById(selector).style.opacity = 1
  selector = ''
}
/* Just for demo */

#board {
  display: grid;
  max-width: 280px;
  background-color: rgb(124, 123, 123);
  grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
  gap: 1px;
}

img {
  width: 50px;
  height: 50px;
}

p {
  margin: 4px 0;
}

.white {
  background-color: #c2bebe;
  width: 50px;
  height: 50px;
}

.black {
  background-color: rgb(78, 52, 52);
  width: 50px;
  height: 50px;
}
<div id="board">
  <p name="a" class="white">
    <img class="icon" id="rw1" src="https://www.gravatar.com/avatar/ab97b60e45a8b300c0436de98c048633?s=64&d=identicon&r=PG&f=1" />
  </p>
  <p name="b" class="black">
    <img class="icon" id="nw1" src="https://www.gravatar.com/avatar/b0ded36026e886f443a5a5adf371c493?s=48&d=identicon&r=PG" />
  </p>
  <p name="a" class="white"></p>
  <p name="b" class="black"></p>
  <p name="c" class="white"></p>
  <p name="d" class="black"></p>
  <p name="e" class="white"></p>
  <p name="f" class="black"></p>
  <p name="g" class="white"></p>
  <p name="h" class="black"></p>
  <p name="i" class="white"></p>
</div>
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement