Search code examples
javascripthtmlcss

Button is not placed on the html div position


I have a JavaScript generated table the user can interact with. Bellow the table, after generating it, a button should be displayed, so it has the display: none after init in my css file.

function createTable(row, col, playerNames) {
    const tbl = document.getElementById("table")
    const tblBody = document.getElementById("tbody")

    // Creating cells
    for (let i = 0; i < row; i++) {
        const row = document.createElement("tr")

        for (let j = 0; j < col; j++) {
            const cell = document.createElement("td")
            if (i == 0 && j == 0) {
                // Create "Runden" cell
                const cellText = document.createTextNode("Runden")
                cell.appendChild(cellText)
            } else if (i == 0 && j != 0) {
                // Create cells with player names in first row
                const cellText = document.createTextNode(playerNames[j])
                cell.appendChild(cellText)
            } else if (i != 0 && j == 0) {
                // Create round counter cells
                const cellText = document.createTextNode(String(i))
                cell.appendChild(cellText)
            } else {
                // Create rest of the cells
                cell.contentEditable = "true"
            }
            row.appendChild(cell)
        }
        if (tblBody) {
            tblBody.appendChild(row)
        }
    }
    if (tbl) {
        // @ts-ignore        
        tbl.appendChild(tblBody)
    }
    // @ts-ignore
    document.body.appendChild(tbl)

    addSumRowToTable(col)

    addEventListenerToTableDataCells()
    
    displayEventCardsButton()
}

function displayEventCardsButton() {
    let eventCardButton = document.getElementById("event_cards")

    if (eventCardButton) {
        eventCardButton.style.display = "block"
    }

}
 <div id="player_count_heading">Anzahl der Spieler eingeben</div>
 <div>
     <table id="table">
         <tbody id="tbody"></tbody>
     </table>
 </div>

 <div class="buttons">
     <button id="player_count" type="button">Spieleranzahl</button>
     <button id="event_cards" type="button">Ereigniskarten</button>
 </div>
  
 <script src="js/frantic.js"></script>

With this code the button is being displayed after generating the table, but it is always appears above the table. The div of the button is placed bellow and so should the button?

I first created the whole table with javascript, but after I encountered this problem, I tried to solve it by clearly positioning the div containers in the html file. But this is also not working out.

Are there any JavaScript/HTML specific things that leads to this behave?

enter image description here


Solution

  • You are selecting an existing table already:

    const tbl = document.getElementById("table")
    

    And because you called this:

    document.body.appendChild(tbl) // Remove this
    

    You are moving the table to the bottom on the body, after the buttons.


    Unless you are actually creating a table like this:

    const tbl = document.createElement("table")
    

    There is no need to append it, and shift its position in the DOM.


    Working snippet

    Here is an updated snippet. I renamed some variables, called append instead of appendChild, and use textContent to simply your logic.

    createTable(10, 5, ["Ann", "Joe", "Mike", "Sam"]);
    
    function createTable(rowCount, colCount, playerNames) {
      const table = document.querySelector("#grid");
      let tbody = table.querySelector("tbody");
      if (tbody == null) {
        tbody = document.createElement("tbody");
        table.append(tbody);
      }
    
      // Populate the table with data
      for (let rowIndex = 0; rowIndex <= rowCount; rowIndex++) {
        const tr = document.createElement("tr");
        for (let colIndex = 0; colIndex < colCount; colIndex++) {
          const td = document.createElement("td");
          if (rowIndex == 0 && colIndex == 0) {
            td.textContent = "Round";
          } else if (rowIndex == 0 && colIndex != 0) {
            // Create cells with player names in first row
            td.textContent = playerNames[colIndex - 1];
          } else if (rowIndex != 0 && colIndex == 0) {
            // Create round counter cells
            td.textContent = rowIndex;
          } else {
            // Create rest of the cells
            td.contentEditable = true;
          }
          tr.append(td);
        }
        tbody.append(tr);
      }
      addSumRowToTable(tbody, colCount);
      addEventListenerToTableDataCells();
      displayEventCardsButton();
    }
    
    function addSumRowToTable(tbody, colCount) {
      const tr = document.createElement("tr");
      for (let colIndex = 0; colIndex < colCount; colIndex++) {
        const td = document.createElement("td");
        if (colIndex === 0) {
          td.textContent = "Sum";
        } else {
          td.textContent = "$";
        }
        tr.append(td);
      }
      tbody.append(tr);
    }
    
    function addEventListenerToTableDataCells() {
      // Not implemented
    }
    
    function displayEventCardsButton() {
      let eventCardButton = document.getElementById("event_cards");
    
      if (eventCardButton) {
        eventCardButton.style.display = "block";
      }
    }
    table#grid {
      border-collapse: collapse;
    }
    
    table#grid, table#grid td {
      border: thin solid grey;
    }
    
    table#grid td {
      padding: 0.25rem;
    }
    
    table#grid tr td:first-child {
      text-align: right;
    }
    <div id="player_count_heading">Anzahl der Spieler eingeben</div>
    <div>
      <table id="grid"></table>
    </div>
    
    <div class="buttons">
      <button id="player_count" type="button">Spieleranzahl</button>
      <button id="event_cards" type="button">Ereigniskarten</button>
    </div>
    
    <script src="js/frantic.js"></script>

    A better way

    Although, here is a better way. You should take advantage of <thead>, <tfoot>, and <th> elements as well. Also, if your function is called "createX", it should probably create and return something.

    const existingTable = document.querySelector("#grid");
    const table = createTable(["Ann", "Joe", "Mike", "Sam"], 10);
    table.id = existingTable.id;
    existingTable.replaceWith(table);
    
    function createTable(playerNames, rounds) {
      const table = document.createElement("table");
      const thead = document.createElement("thead");
      const tbody = document.createElement("tbody");
      const tfoot = document.createElement("tfoot");
    
      const colCount = playerNames.length + 1;
    
      const headerRow = document.createElement("tr");
      for (let colIndex = 0; colIndex < colCount; colIndex++) {
        const header = document.createElement("th");
        header.textContent = colIndex === 0 ? "Round" : playerNames[colIndex - 1];
        headerRow.append(header);
      }
      thead.append(headerRow);
    
      // Populate the table with data
      for (let rowIndex = 0; rowIndex < rounds; rowIndex++) {
        const tr = document.createElement("tr");
        for (let colIndex = 0; colIndex < colCount; colIndex++) {
          if (colIndex === 0) {
            // Create round counter cells
            const th = document.createElement("th");
            th.textContent = rowIndex + 1;
            tr.append(th);
          } else {
            // Create rest of the cells
            const td = document.createElement("td");
            td.contentEditable = true;
            tr.append(td);
          }
        }
        tbody.append(tr);
      }
    
      table.append(thead);
      table.append(tbody);
      table.append(tfoot);
    
      addSumRowToTable(tfoot, playerNames.length + 1);
      addEventListenerToTableDataCells();
      displayEventCardsButton();
    
      return table;
    }
    
    function addSumRowToTable(tfoot, colCount) {
      const tr = document.createElement("tr");
      for (let colIndex = 0; colIndex < colCount; colIndex++) {
        if (colIndex === 0) {
          // Create round counter cells
          const th = document.createElement("th");
          th.textContent = "Sum";
          tr.append(th);
        } else {
          // Create rest of the cells
          const td = document.createElement("td");
          td.textContent = "$";
          tr.append(td);
        }
      }
      tfoot.append(tr);
    }
    
    function addEventListenerToTableDataCells() {
      // Not implemented
    }
    
    function displayEventCardsButton() {
      let eventCardButton = document.getElementById("event_cards");
    
      if (eventCardButton) {
        eventCardButton.style.display = "block";
      }
    }
    table#grid {
      border-collapse: collapse;
    }
    
    table#grid, table#grid th, table#grid td {
      border: thin solid grey;
    }
    
    table#grid th, table#grid td {
      padding: 0.25rem;
    }
    
    table#grid tbody tr th:first-child {
      text-align: right;
      background: #EEE;
    }
    
    table#grid thead {
      background: #CCC;
    }
    
    table#grid tfoot {
      background: #EEE;
    }
    <div id="player_count_heading">Anzahl der Spieler eingeben</div>
    <div>
      <table id="grid"></table>
    </div>
    
    <div class="buttons">
      <button id="player_count" type="button">Spieleranzahl</button>
      <button id="event_cards" type="button">Ereigniskarten</button>
    </div>
    
    <script src="js/frantic.js"></script>