DrAhzek
DrAhzek

Reputation: 195

Javascript - using buttons in generated table for showcasing information in aside element

I'm currently trying to figure out the way to expand my dynamically generated table with buttons. Said buttons would be showing (on click) some parts of the informations from the table in the aside element from HTML of a page in question. For example - when I click a button in first row, it's showing me name of a product in this row in the aside block next to the table. The idea is simple, the execution not so much.

Creating aside element isn't a rocket science but creating dynamic buttons that can showcase parts of a dynamic table is a bit problematic for me. Below is a full code responsible for the creation of the table.

 window.onload = function(e) {
    createBook("book");
  }
var books = [{
    "author": "Eric T. Freeman",
    "title": "Head First JavaScript Programming: A Brain-Friendly Guide",
    "isbn": "978-1-4493-4398-9, 9781449343989",
    "publisher": "O'Reilly Media",
    "editions": [{
        "year": "2017",
        "covercolour": "gray"
      },
      {
        "year": "2014",
        "covercolour": "blue"
      }
    ]
  },
  {
    "author": "David Flanagan",
    "title": "JavaScript: The Definitive Guide",
    "isbn": "0596805527",
    "publisher": "O'Reilly Media",
    "editions": [{
        "year": "2016",
        "covercolour": "yellow"
      },
      {
        "year": "2011",
        "covercolour": "black"
      }
    ]
  }
];

function createBook(bookid) {
  var bookbox = document.getElementById(bookid);

  article = document.createElement("article");
  bookbox.appendChild(article);

  sectionInfo = createSection("List of Books");
  article.appendChild(sectionInfo);

  var infoTable = createTableBook(book);
  sectionInfo.appendChild(infoTable);

}

function createTableBook() {
  var table = document.createElement("table");
  table.classList.add("tableBasic");
  var tr = document.createElement("tr");
  var th1 = document.createElement("th");
  var th2 = document.createElement("th");
  var th3 = document.createElement("th");
  var th4 = document.createElement("th");
  var th5 = document.createElement("th");
  var th6 = document.createElement("th");
  th1.innerHTML = "Author";
  th2.innerHTML = "Title";
  th3.innerHTML = "ISBN";
  th4.innerHTML = "Publisher";
  th5.innerHTML = "Editions";
  th6.innerHTML = "Showcase";
  tr.appendChild(th1);
  tr.appendChild(th2);
  tr.appendChild(th3);
  tr.appendChild(th4);
  tr.appendChild(th5);
  tr.appendChild(th6);
  table.appendChild(tr);

  for (var index in books) {
    var tr = document.createElement("tr");
    var td1 = document.createElement("td");
    td1.innerHTML = books[index].author;
    tr.appendChild(td1);
    var td2 = document.createElement("td");
    td2.innerHTML = books[index].title;
    tr.appendChild(td2);
    var td3 = document.createElement("td");
    td3.innerHTML = books[index].isbn;
    tr.appendChild(td3);
    var td4 = document.createElement("td");
    td4.innerHTML = books[index].publisher;
    tr.appendChild(td4);
    var td5 = document.createElement("td");
 //   td5.appendChild(createEditionDetails(index));
    tr.appendChild(td5);
    var td6 = document.createElement("button");
    td6.innerHTML = "button";
    tr.appendChild(td6);
    table.appendChild(tr);
}
return table;
}

function buttonWork(asideID) {//function I want to use
    var aside = document.getElementById(asideID);

    var $row = $(this).closest("tr");
    var $text = $row.find(".name").text();
    aside.innerHTML += $text + '<br/>';
}
function createHeader(h, text) {
  header = document.createElement("header");
  h = document.createElement(h);
  h.innerHTML = text;
  header.appendChild(h);
  return header;
}

function createSection(title) {
  var section = document.createElement("section");
  section.appendChild(createHeader("h3", title));
  return section;
}
<section>
  <article>
    <aside>
      <br>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    </aside>
    <section id="book">
    </section>
  </article>
</section>
<!--<script>
  window.onload = function(e) {
    createBook("book");
  }
</script>-->

After some trial and error, I was able to find a solution to some of my problems but I can't find a way to reliably connect buttons to the new logic in buttonWork function. I could use some ideas for a newbie in JS.

Upvotes: 0

Views: 77

Answers (2)

Scott Marcus
Scott Marcus

Reputation: 65806

First, your code needs to be corrected because all table content must go into a cell (th or td). You currently have your button elements being appended directly to rows. But, after that correction, this is simpler than you think.

  • Set up just one click event handler on the table and when each generated button is clicked, that event will bubble up to the table and be handled there. (event delegation)
  • To distinguish one piece of information from another, each cell will have a class associated with it.
  • In the click handler we'll locate the information that is relative to the button that was clicked using the .closest() and .querySelector() methods and display it in the aside.

On a side note, don't use .innerHTML when you aren't setting/getting any content that contains HTML. There are performance and security concerns to its use. Instead, use .textContent.

Finally, the code you are showing isn't using images or external resources, so having it all trigger on the .load event, while functional, is not the best choice. Instead, have your code initiate as soon as the browser has finished parsing the HTML in the body. The simplest way to make that happen is to just place your code just prior to the closing body tag.

table {
 font-size:.8em;
 border:2px solid #363;
 font-family:Arial, Calibri, Helvetica;
}

th, td {
  border:1px solid #e0e0e0;
  padding:2px;
}
<body>
  <section>
    <article>
      <aside>
        <br>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
      </aside>
      <section id="book">
      </section>
    </article>
  </section>

  <!-- Placing your script here ensures that it won't run until all the HTML
       above it has been parsed and the DOM is fully loaded. -->
  <script>
  
    // Object property/key names do not need to be in quotes unless they contain spaces
    var books = [{
        author: "Eric T. Freeman",
        title: "Head First JavaScript Programming: A Brain-Friendly Guide",
        isbn: "978-1-4493-4398-9, 9781449343989",
        publisher: "O'Reilly Media",
        editions: [{year: "2017", covercolour:"gray" },{year: "2014", covercolour:"blue"}]
      },
      {
        author: "David Flanagan",
        title: "JavaScript: The Definitive Guide",
        isbn: "0596805527",
        publisher: "O'Reilly Media",
        editions: [{year: "2016", covercolour:"yellow"},{year:"2011", covercolour:"black"}]
      }];

    function createBook(bookid) {
      var bookbox = document.getElementById(bookid);

      article = document.createElement("article");
      bookbox.appendChild(article);

      sectionInfo = createSection("List of Books");
      article.appendChild(sectionInfo);

      var infoTable = createTableBook(book);
      sectionInfo.appendChild(infoTable);
    }

    function createTableBook() {
      var table = document.createElement("table");
      table.classList.add("tableBasic");
      var tr = document.createElement("tr");
      var th1 = document.createElement("th");
      var th2 = document.createElement("th");
      var th3 = document.createElement("th");
      var th4 = document.createElement("th");
      var th5 = document.createElement("th");
      var th6 = document.createElement("th");
      th1.textContent = "Author";
      th2.textContent = "Title";
      th3.textContent = "ISBN";
      th4.textContent = "Publisher";
      th5.textContent = "Editions";
      th6.textContent = "Showcase";
      tr.appendChild(th1);
      tr.appendChild(th2);
      tr.appendChild(th3);
      tr.appendChild(th4);
      tr.appendChild(th5);
      tr.appendChild(th6);
      table.appendChild(tr);

      // Books is an array, for/in loops are for objects.
      // With Arrays, there are many different types of loops available, but .forEach()
      // is the simplest as it does away with indexers
      books.forEach(function(book){
        var tr = document.createElement("tr");
        var td1 = document.createElement("td");
        td1.textContent = book.author;
        td1.classList.add("author");   // <-- This will be used to locate the data you want to show
        tr.appendChild(td1);
    
        var td2 = document.createElement("td"); 
        td2.textContent = book.title;
        td2.classList.add("title");  // <-- This will be used to locate the data you want to show       
        tr.appendChild(td2);
    
        var td3 = document.createElement("td");
        td3.textContent = book.isbn;
        td3.classList.add("isbn");   // <-- This will be used to locate the data you want to show       
        tr.appendChild(td3);
    
        var td4 = document.createElement("td");
        td4.textContent = book.publisher;
        td4.classList.add("publisher");  // <-- Used to locate the data you want to show           
        tr.appendChild(td4);
    
        var td5 = document.createElement("td");
        // td5.appendChild(createEditionDetails(index));
        td5.classList.add("edition");   // <-- This will be used to locate the data you want to show   
        tr.appendChild(td5);
    
        // All table content must be contained inside of cells. You have to put your button in 
        // a cell and then that cell goes into the row.
        var td6 = document.createElement("td");
        var btn = document.createElement("button");
        btn.textContent = "Details";
        td6.appendChild(btn);
        tr.appendChild(td6);
    
        table.appendChild(tr);
      });
      return table;
    }

    function createHeader(h, text) {
      header = document.createElement("header");
      h = document.createElement(h);
      h.textContent = text;
      header.appendChild(h);
      return header;
    }

    function createSection(title) {
      var section = document.createElement("section");
      section.appendChild(createHeader("h3", title));
      return section;
    }
  
    createBook("book");
    
    // You'll need to reference the table and the aside more than once.
    // Just query for them one time and then keep referring to those variables:
    let tbl = document.querySelector("table");
    let side = document.querySelector("aside");

    // Any buttons within the table that get clicked will also cause a click event to 
    // trigger for the table itself. We'll handle the details there.
    tbl.addEventListener("click", function(evt){
      // Set the aside's text content by navigating to the clicked button's closest
      // (<tr>) and then query from there to find the cell with the desired class.
      // Here, we're showing the title in the aside, but you can substitute any of the other 
      // book data by just referring to the class that was assigned to the cell.
      side.textContent = evt.target.closest("tr").querySelector(".title").textContent;
    });
  </script>
</body>

Upvotes: 1

Rachel Gallen
Rachel Gallen

Reputation: 28563

If you want to show information on click, you could use either a button/input or a hyperlink (on your first column) to make the row/column clickable

The following piece of code illustrates how to make a button

var td1 = document.createElement('input');
td1.type = "button";
td1.className = "btn";
td1.value = books[index].author;
td1.onclick = (function() {write your function here});
td.appendChild(td1);

Using your existing code you could make a column (in this case, the first) into a button by tweaking your code to reflect that the innerHTML would be a button (see bolded code), as opposed to adding an extra column of buttons to the table.

I would recommend adding identifiers to the columns. See fiddle to illustrate what I mean (shows button being added to 'Author' column)

The most important thing will be what you write in the function. It is not clear what you want to do here, but if you want to write to another section, then get that section by calling it by it's id and then write in the values.

Hope this helps

 window.onload = function(e) {
    createBook("book");
  }
var books = [{
    "author": "Eric T. Freeman",
    "title": "Head First JavaScript Programming: A Brain-Friendly Guide",
    "isbn": "978-1-4493-4398-9, 9781449343989",
    "publisher": "O'Reilly Media",
    "editions": [{
        "year": "2017",
        "covercolour": "gray"
      },
      {
        "year": "2014",
        "covercolour": "blue"
      }
    ]
  },
  {
    "author": "David Flanagan",
    "title": "JavaScript: The Definitive Guide",
    "isbn": "0596805527",
    "publisher": "O'Reilly Media",
    "editions": [{
        "year": "2016",
        "covercolour": "yellow"
      },
      {
        "year": "2011",
        "covercolour": "black"
      }
    ]
  }
];

function createBook(bookid) {
  var bookbox = document.getElementById(bookid);

  article = document.createElement("article");
  bookbox.appendChild(article);

  sectionInfo = createSection("List of Books");
  article.appendChild(sectionInfo);

  var infoTable = createTableBook(book);
  sectionInfo.appendChild(infoTable);

}

function createTableBook() {
  var table = document.createElement("table");
  table.classList.add("tableBasic");
  var tr = document.createElement("tr");
  var th1 = document.createElement("th");
  var th2 = document.createElement("th");
  var th3 = document.createElement("th");
  var th4 = document.createElement("th");
  var th5 = document.createElement("th");
  var th6 = document.createElement("th");
  th1.innerHTML = "Author";
  th2.innerHTML = "Title";
  th3.innerHTML = "ISBN";
  th4.innerHTML = "Publisher";
  th5.innerHTML = "Editions";
  th6.innerHTML = "Showcase";
  tr.appendChild(th1);
  tr.appendChild(th2);
  tr.appendChild(th3);
  tr.appendChild(th4);
  tr.appendChild(th5);
  tr.appendChild(th6);
  table.appendChild(tr);

  for (var index in books) {
    var tr = document.createElement("tr");
    var td1 = document.createElement("td");
    **td1.innerHTML = '<input type="button" value ="' + books[index].author + '"' +'/>';**
    tr.appendChild(td1);
    var td2 = document.createElement("td");
    td2.innerHTML = books[index].title;
    tr.appendChild(td2);
    var td3 = document.createElement("td");
    td3.innerHTML = books[index].isbn;
    tr.appendChild(td3);
    var td4 = document.createElement("td");
    td4.innerHTML = books[index].publisher;
    tr.appendChild(td4);
    var td5 = document.createElement("td");
 //   td5.appendChild(createEditionDetails(index));
    tr.appendChild(td5);
    var td6 = document.createElement("td"); //a column reserved for buttons
//    td6.appendChild(createButtonShow(index)); //I suppose it's going to be a similar index requirement as in createEditionDetails function
    tr.appendChild(td6);
    table.appendChild(tr);
  }
  return table;
}

function createHeader(h, text) {
  header = document.createElement("header");
  h = document.createElement(h);
  h.innerHTML = text;
  header.appendChild(h);
  return header;
}

function createSection(title) {
  var section = document.createElement("section");
  section.appendChild(createHeader("h3", title));
  return section;
}
<section>
  <article>
    <aside>
      <br>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    </aside>
    <section id="book">
    </section>
  </article>
</section>
<!--<script>
  window.onload = function(e) {
    createBook("book");
  }
</script>-->

Upvotes: 0

Related Questions