Search code examples
javascripthtmlhtml-tablecellpersistent

Large HTML table and repeated cell creation using Javascript


I'm sure this has to be documented somewhere, but I'm so new at html that I can't figure out where to look, so feel free to just direct me to the correct reading if it's something obvious. As a note, I code in several languages, but mostly things like python or LaTeX, nothing like html. I have included my attempt at the bottom, but tried to include what I could in terms of my design setup and what problems I am running into. Any solutions to any of the listed problems would be appreciated :)

The setup;

I need to form gigantic table of information that will be populated based on a JSON string given on another webpage. I am currently using javascript to parse the JSON string and form a single global object of my own that has all the relevant information (the JSON string that the user will plug in is huge and I only need a relatively small portion of it). The created object has the following form;

  cruData = {hero:[{"cruID":0,"EP":0,"Owned":"No","GearName1":"Empty","GearRarity1":"Empty","GearName2":"Empty","GearRarity2":"Empty","GearName3":"Empty","GearRarity3":"Empty"}]}

With the cruID iterating from 0 to 103 (plans to make it at least a couple hundred higher at some point). All the strings will be populated with strings, and EP/ID are true numbers.

Proposed Setup:

My original plan was to pre-make the (blank) table structure on the separate web page, and then after grabbing the JSON file and parsing it into the cruData object, to populate that table with relevant info (technically ID 1 to 103 for now, no 0 ID in this table) upon page-load when the user goes to it.

The Problems:

1) My concern with this method of forming the table upon page load is that the table is sizable and I'd really rather not have the table get formed on every page load. Is there a way to save this locally so that it gets formed once and then it's in cache?

2) Assuming pre-formatting the table really is a good idea (feel free to tell me I'm stupid for thinking so heh), I will have some 350+ cells (all the 'rarity' cells) that are all identical dropdown boxes. Thus I'd like to make a class type for cells that are a drop-down selection list, but can't figure out how to do that in the style section. I can get a specific td to work, but not a class of td to work. Again, I'm sure this is because I just don't really understand how defining classes or the style section works (I haven't used a class-inheritance system coding before).

To be specific, I would like there to be a drop-down box in 3 different cells of every row of this 100+ row table. They are all identical drop-down selections. To do this, would a form be better? Is there a way to define the drop-down selections one time in a class, and then just point to the class in each cell so that I don't have to re-add the selection options to 3 cells of every single row?

3) I would like each of the rarity cells and the EP cell for each row to be editable by the human, having the new value saved for calculations elsewhere. My idea for this would be to copy the cruData object to a cruComp object that is used for computations, then have that get overwritten by player input; that way I can add a "reset" button on the table page to fix everything back after user remorse kicks in :)

4) I want to color row blocks in the table that correspond to something in the game I'm recording data for. Right now I need every 5 rows to be blocked together in a color after the heading, but that 5 may universally change to another number. Is there a way to set a dynamic variable for this so that I can change one number instead of a bunch? Also in my attempt below it works for the first like 50-70 rows and then starts having all kinds of weird behavior, but I can't figure out why? [ Solved, found the thead tbody tags which was the problem ]

5) Not a real problem but, is there a way to just have x rows get created without each one being created by hand? The only wrinkle is that the ID numbers in the example given below will have all the numbers 1-103+ but not in that order. I figured I could do some sort of vector that has the numbers in the correct order and then pull the consecutive numbers from that vector in order to number them in order, but I don't know if you can create rows using a FOR loop.

Thanks for the help!

My Attempt: Warning, I'm sure this will make anyone that knows what they are doing die inside, as I keep saying I really have little to no idea what I'm doing in this language. Hence me starting with a silly project to learn by doing :)

<!DOCTYPE html>
<html>
<head>
  <title>COTLI Calculator and Ref</title>
<!--  <link rel="stylesheet" href="StyleRef.css"> -->

 <script>
   function Load_Data() {
    var i = 0;

/*
         <td>The Bush Whacker</td>
         <td id="CrEP_1">Blank</td>
         <td id="CrGN1_1">Blank</td>
         <td id="CrGR1_1">Blank</td>
         <td id="CrGN2_1">Blank</td>
         <td id="CrGR2_1">Blank</td>
         <td id="CrGN3_1">Blank</td>
         <td id="CrGR3_1">Blank</td>
         <td id="CrUnLock_1">Blank</td>
*/
  for (i = 1; i < lootTable.hero.length; i++) {
  "crEP_"+i = cruData.hero[i].EP;
  };
 }

   window.onload = Load_Data;

 </script>


</head>


<body style="background-color:lightgrey; text-align:center;">


  <style>
<!-- Below is the color coding for the rows broken into batches of 4 bench slots at a time. The offset value is because of how the rows are counted and the "header" row. -->
<!--  tr:nth-child(35n+1) {background-color: #4682b4;} -->
<!--  tr:nth-child(21n+1) {background-color: #e36f8a;} -->

  tr:nth-child(20n+2) {background-color: #4682b4;}
  tr:nth-child(20n+3) {background-color: #4682b4;}
  tr:nth-child(20n+4) {background-color: #4682b4;}
  tr:nth-child(20n+5) {background-color: #4682b4;}
  tr:nth-child(20n+6) {background-color: #4682b4;}

  tr:nth-child(20n+7) {background-color: #3abda0;}
  tr:nth-child(20n+8) {background-color: #3abda0;}
  tr:nth-child(20n+9) {background-color: #3abda0;}
  tr:nth-child(20n+10) {background-color: #3abda0;}
  tr:nth-child(20n+11) {background-color: #3abda0;}

  tr:nth-child(20n+12) {background-color: #e09e87;}
  tr:nth-child(20n+13) {background-color: #e09e87;}
  tr:nth-child(20n+14) {background-color: #e09e87;}
  tr:nth-child(20n+15) {background-color: #e09e87;}
  tr:nth-child(20n+16) {background-color: #e09e87;}

  tr:nth-child(20n+17) {background-color: #93b881;}
  tr:nth-child(20n+18) {background-color: #93b881;}
  tr:nth-child(20n+19) {background-color: #93b881;}
  tr:nth-child(20n) {background-color: #93b881;}
  tr:nth-child(20n+1) {background-color: #93b881;}


    table {
      border-collapse: collapse;
      border: 5px solid black;
      tex-align:center;
    }
    th {
      padding: 20px;
      border: solid black 3px;
    }

    td {
      padding: 20px;
      border: solid black 1px;
    }

    td.rarity {
      <select>
        <option value="volvo">Volvo</option>
        <option value="saab">Saab</option>
        <option value="mercedes">Mercedes</option>
        <option value="audi">Audi</option>
      </select>
    }

  </style>

  <h1>
    Crusader Table
  </h1>

  <table align="center">
     <tr style="background-color:#e36f8a; text-align:center;">
         <th>Crusader Name</th>
         <th>EP</th>
         <th>Gear 1 Name</th>
         <th>Gear 1 Rarity</th>
         <th>Gear 2 Name</th>
         <th>Gear 2 Rarity</th>
         <th>Gear 3 Name</th>
         <th>Gear 3 Rarity</th>
         <th>Unlocked</th>
    </tr>
    <!-- Below is the master table for Crusaders. Tags are: CrEP_# for EP, CrGN1_# for Gear 1 name, CrGR1_# for Gear 1 Rarity (similarly gear 2 and 3) and CrUnlock_# for unlock, where # is Crusader ID. -->

<!-- Bench One

The Bush Whacker - 1
RoboRabbit - 38
Graham The Driver - 66
Warwick the Warlock - 75
Slisiblyp, the Alien Scientist - 89
-->
<tr>
     <td>The Bush Whacker</td>
     <td id="CrEP_1" value=CruData.hero[1].EP> </td>
     <td id="CrGN1_1">Blank</td>
     <td class="rarity" id="CrGR1_1"></td>
     <td id="CrGN2_1">Blank</td>
     <td id="CrGR2_1">Blank</td>
     <td id="CrGN3_1">Blank</td>
     <td id="CrGR3_1">Blank</td>
     <td id="CrUnLock_1">Blank</td>
</tr>

Solution

  • Without doing it for you - here are the angles that I would solve these problems

    1. You can cache it locally to a cookie as a string of the literal HTML, but the process really isn't that expensive. If the length is a concern - maybe think about breaking it down into rendering the first X amount of elements.

    2. Create a class for the cell. <td class='dropdown-cell'> [your data] </td> and then in your css: .dropdown-cell{[your css rules} will format only the table cells that have the class dropdown-cell. edit: CSS classes work the same way they would if it was a <td class="custom-class"> or <select class="custom-class"> or <option class="custom-class> whatever element you put it on will inherit that styling as specified by .custom-class in the CSS.

    .dropdown{
      height: 50px;
      width: 200px;
      background-color: gray;
    }
    
    .dropdown-option{
      background-color: lightgray;
    }
    <select class="dropdown">
      <option class="dropdown-option">A</option>
      <option class="dropdown-option">B</option>
      <option class="dropdown-option">C</option>
    </select>

    1. If I'm understanding it right, if you want these edits to be bound to some object. You should create a class for each row, and then run a function onChange or onClick or onKeyup of these editable events and modify the related Object.

    class SomeObject{
      constructor(id, name, someVal){
        this.id = id;
        this.name = name; 
        this.someVal = someVal;
      }
    }
    
    var numberOfObjects = 5;
    var yourObjectsArray = [];
    
    //Create i number of objects and add them to an array of your row objects
    //This would be done by looping through your JSON
    for(var i = 0; i < numberOfObjects; i++){
      yourObjectsArray.push(new SomeObject(i, "Object " + i, "Some Value")); 
    }
    
    
    
    //Build your table
    for(var i = 0; i < yourObjectsArray.length; i++){
      //The syntax below is Jquery - I suggest using it for event bindings and DOM manipulation
      $('#output-table').append('<tr><td class="id">'+ yourObjectsArray[i].id +'</td><td>'+ yourObjectsArray[i].name +'</td><td class="change-val">'+ yourObjectsArray[i].someVal +'</td></tr>');
    }
    
    //Bind an event to a click or any jquery event handler
    $(document).on('click', '.change-val', function(){
      //Get the ID of the row that you clicked
      var id = $(this).closest('tr').find('.id').text(); //use value or something else
      
      //Modify the text in the table
      var newVal = "New Value";
      $(this).text(newVal);
      
      //Parse the array of objects to find the one you need to modify
      for(var i = 0; i < yourObjectsArray.length; i++){
        if(yourObjectsArray[i].id == id){
          yourObjectsArray[i].someVal = newVal;
        }
      }
      
      //Prove that your object value changed not just the text
      $('#output').html("<br>");//clear the output
      for(var i = 0; i < yourObjectsArray.length; i++){
        $('#output').append('ID: ' + yourObjectsArray[i].id + " Value: " + yourObjectsArray[i].someVal + "<br>");
      }
      
      
    });
    table {
        border-collapse: collapse;
    }
    
    table, th, td {
        border: 1px solid black;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    Click on a value cell below to change it
    <table id="output-table">
    <thead>
      <tr>
        <td>ID</td>
        <td>Name</td>
        <td>Value</td>
      </tr>
    </thead>
    </table>
    
    <div id="output"></div>

    1. https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName add a class to each row and then in a for loop, add conditional formatting for row[i] modulus 5.

    2. You can create rows using a for loop, you just have to give the Javascript the HTML formatting and then use an append to add it to the end https://www.w3schools.com/jsref/met_node_appendchild.asp

    I'd recommend Jquery for your DOM manipulation as it makes drilling down to specific ID's, classes, and elements very easy.