Tylerr
Tylerr

Reputation: 173

Reformatting HTML Table

I currently have a basic html table that can sort by column, for example it looks like:

id | stationname | total
-------------------------
 1 | Khar        | 5
 2 | SantaCruz   | 3
 3 | Sion        | 2
 4 | VT          | 1
 5 | newFort     | 3
 6 | Bandra      | 2

But what I want is to display in a format similar to how products are displayed on a website, so:

Khar | SantaCruz | Sion
1    | 2         | 3
5    | 3         | 2

VT   | newFort   | Bandra 
4    | 5         | 6
1    | 3         | 2

But still retain the ability to sort by "id" "stationame" and "total". I appreciate any help!

Upvotes: 0

Views: 87

Answers (2)

Jon P
Jon P

Reputation: 19772

You haven't given us much to work with so I've cobbled the following together making some assumptions. The biggest of which is that you have a json data source.

The following is fairly flexible, you can change the layout with the basic html and css. The only real dependencies through to the javasctipt is the class names which are used for data binding and sorting.

Basically what we have happening is a template that is not rendered courtesy of wrapping it in <script type="text/template" id="stationsTemplate">. We also have a json representation that we can sort using the dynamicSort method. Finally we use event delegation to handle the click events for the dynamically added elements.

/*Table Data*/
var stations = [{
    id: 1,
    name: "Khar",
    total: 5
  },
  {
    id: 2,
    name: "SantaCruz",
    total: 3
  },
  {
    id: 3,
    name: "Sion",
    total: 2
  },
  {
    id: 4,
    name: "VT",
    total: 1
  },
  {
    id: 5,
    name: "newFort",
    total: 3
  },
  {
    id: 6,
    name: "Bandra",
    total: 2
  }
];

/*Performs the sort on the obect property passed*/
function dynamicSort(property) {

  return function(a, b) {
    var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
    return result;
  }
}

//Generates the list
function generateList(sortedStations) {
  //Set Up the template
  var s = document.getElementById("stationsTemplate").innerHTML.trim();

  var holder = document.createElement('div');
  holder.innerHTML = s;
  var template = holder.childNodes;


  var stations = document.getElementById('stations');
  stations.innerHTML = "";
  sortedStations.forEach(function(object) {

    //Clone Template
    var newItem = template[0].cloneNode(true);

    //Populate it
    newItem.querySelector(".name").innerHTML = object.name;
    newItem.querySelector(".id").innerHTML = object.id;
    newItem.querySelector(".total").innerHTML = object.total;
    //Append it    
    document.getElementById("stations").appendChild(newItem);

  });
}

//Add event listener to the list and then use event delegation
document.getElementById("stations").addEventListener('click', function(e) {

  if (e.target) {
    var sortKey = "";
    if (e.target.classList.contains("lblId")) {
      sortKey = "id";
    } else if (e.target.classList.contains("lblName")) {
      sortKey = "name";
    } else if (e.target.classList.contains("lblTotal")) {
      sortKey = "total";
    }
  }

  if (sortKey !== "") {
    generateList(stations.sort(dynamicSort(sortKey)));
  }
});

//Initial build
generateList(stations);
#stations {
  list-style: none;
  padding: 0;
}

#stations li {
  display: inline-block;
  width: 250px;
  margin: 10px;
  background-color: #CCC;
  padding: 5px;
  vertical-align: top;
}

#stations label {
  font-weight: bold;
  cursor: pointer;
}
Click on label to sort
<ul id="stations">

</ul>

<!-- Template for our stations -->
<script type="text/template" id="stationsTemplate">
  <li>
    <div><label class="lblName">Name:</label> <span class="name"></span></div>
    <div><label class="lblId">Id: </label><span class="id"></span></div>
    <div><label class="lblTotal">Total: </label><span class="total"></span></div>
  </li>
</script>

Yes this can be optimized but it should be good enough for a starting point

Alternately you can use the following

This does not rely on an existing data structure, but sorts the actual DOM nodes in an array.

Again you can change the layout via html and css. The class names are used to identify the sort key and sort values.

/*Performs the sort on the obect property passed*/
function dynamicSort(property) {

  return function(a, b) {
    var selector = "." + property;
    var aVal = a.querySelector(selector).innerHTML;
    var bVal = b.querySelector(selector).innerHTML;

    //Convert to number if appropriate - adjust if you need other data types
    if (!isNaN(aVal) && !isNaN(bVal)) {
      aVal = parseFloat(aVal);
      bVal = parseFloat(bVal);
    }

    var result = (aVal < bVal) ? -1 : (aVal > bVal) ? 1 : 0;
    return result;
  }
}

//Generates the list
function sortList(sortKey) {
  //Convert Node LIst to array 
  var arrItems = Array.prototype.slice.call(document.querySelectorAll("#stations li"));

  //Sort using our key
  arrItems.sort(dynamicSort(sortKey));

  //Append to original list
  var list = document.getElementById("stations");
  for (var i = 0; i < arrItems.length; i++) {
    list.appendChild(arrItems[i]);
  }
}

//Add event listener to the list and then use event delegation
document.getElementById("stations").addEventListener('click', function(e) {

  if (e.target) {
    var sortKey = "";
    if (e.target.classList.contains("lblId")) {
      sortKey = "id";
    } else if (e.target.classList.contains("lblName")) {
      sortKey = "name";
    } else if (e.target.classList.contains("lblTotal")) {
      sortKey = "total";
    }
  }

  if (sortKey !== "") {
    sortList(sortKey);
  }
});
#stations {
  list-style: none;
  padding: 0;
}

#stations li {
  display: inline-block;
  width: 250px;
  margin: 10px;
  background-color: #CCC;
  padding: 5px;
  vertical-align: top;
}

#stations label {
  font-weight: bold;
  cursor: pointer;
}
Click on label to sort
<ul id="stations">
  <li>
    <div><label class="lblName">Name:</label> <span class="name">Khar</span></div>
    <div><label class="lblId">Id: </label><span class="id">1</span></div>
    <div><label class="lblTotal">Total: </label><span class="total">5</span></div>
  </li>
  <li>
    <div><label class="lblName">Name:</label> <span class="name">SantaCruz</span></div>
    <div><label class="lblId">Id: </label><span class="id">2</span></div>
    <div><label class="lblTotal">Total: </label><span class="total">3</span></div>
  </li>
  <li>
    <div><label class="lblName">Name:</label> <span class="name">Sion</span></div>
    <div><label class="lblId">Id: </label><span class="id">3</span></div>
    <div><label class="lblTotal">Total: </label><span class="total">2</span></div>
  </li>
  <li>
    <div><label class="lblName">Name:</label> <span class="name">VT</span></div>
    <div><label class="lblId">Id: </label><span class="id">4</span></div>
    <div><label class="lblTotal">Total: </label><span class="total">1</span></div>
  </li>
  <li>
    <div><label class="lblName">Name:</label> <span class="name">newFort</span></div>
    <div><label class="lblId">Id: </label><span class="id">5</span></div>
    <div><label class="lblTotal">Total: </label><span class="total">3</span></div>
  </li>
  <li>
    <div><label class="lblName">Name:</label> <span class="name">Bandra</span></div>
    <div><label class="lblId">Id: </label><span class="id">6</span></div>
    <div><label class="lblTotal">Total: </label><span class="total">2</span></div>
  </li>
</ul>

Upvotes: 2

Dženis H.
Dženis H.

Reputation: 7822

IMHO, I think for an e-commerce alike view you should go with a gallery based Grid system. Here a did a shoe category type of presentation where you can sort by the brand. But obviously, you could add all kinds of sorting/ filtering capabilities. @JonP nailed it with his answer, I just wanted to take an alternative approach. But like he said, "You haven't given us much to work with" Maybe you don't even want an e-commerce type of view and you were just using it as a comparison, but who knows? Maybe it will be helpful to you or someone in the future. Run the code snippet to see if that works for you :)

filterSelection("all") // Execute the function and show all columns
function filterSelection(c) {
  let x, i;
  x = document.getElementsByClassName("column");
  if (c == "all") c = "";
  // Add the "show" class (display:block) to the filtered elements, and remove the "show" class from the elements that are not selected
  for (i = 0; i < x.length; i++) {
    removeClass(x[i], "show");
    if (x[i].className.indexOf(c) > -1) addClass(x[i], "show");
  }
}

// Show filtered elements
function addClass(element, name) {
  let i, arr1, arr2;
  arr1 = element.className.split(" ");
  arr2 = name.split(" ");
  for (i = 0; i < arr2.length; i++) {
    if (arr1.indexOf(arr2[i]) == -1) {
      element.className += " " + arr2[i];
    }
  }
}

// Hide elements that are not selected
function removeClass(element, name) {
  let i, arr1, arr2;
  arr1 = element.className.split(" ");
  arr2 = name.split(" ");
  for (i = 0; i < arr2.length; i++) {
    while (arr1.indexOf(arr2[i]) > -1) {
      arr1.splice(arr1.indexOf(arr2[i]), 1); 
    }
  }
  element.className = arr1.join(" ");
}

// Add active class to the current button (highlight it)
const btnContainer = document.getElementById("myBtnContainer");
const btns = btnContainer.getElementsByClassName("btn");
for (let i = 0; i < btns.length; i++) {
  btns[i].addEventListener("click", function(){
    let current = document.getElementsByClassName("active");
    current[0].className = current[0].className.replace(" active", "");
    this.className += " active";
  });
}
* {
    box-sizing: border-box;
}

body {
    background-color: #f1f1f1;
    padding: 20px;
    font-family: Arial;
}

/* Center website */
.main {
    max-width: 1000px;
    margin: auto;
}

h2 {
    font-size: 2rem;
    word-break: break-all;
    color: #006400;
    font-family: Cursive;
    letter-spacing: 6px;
}

.row {
    margin: 8px -16px;
}

/* Add padding BETWEEN each column (if you want) */
.row,
.row > .column {
    padding: 8px;
}

/* Create three equal columns that floats next to each other */
.column {
    float: left;
    width: 33.33%;
    display: none; /* Hide columns by default */
}

/* Clear floats after rows */ 
.row:after {
    content: "";
    display: table;
    clear: both;
}

/* Content */
.content {
    background-color: white;
    padding: 10px;
}

/* The "show" class is added to the filtered elements */
.show {
    display: block;
}

/* Style the buttons */
.btn {
  border: none;
  outline: none;
  padding: 12px 16px;
  background-color: white;
  cursor: pointer;
}

/* Add a grey background color on mouse-over */
.btn:hover {
  background-color: #00FF64;
  font-weight: bold;
}

/* Add a dark background color to the active button */
.btn.active {
  background-color: #228B22;
   color: white;
}
<h2>Shoes Section</h2>
<div id="myBtnContainer">
  <button class="btn active" onclick="filterSelection('all')"> Show all</button>
  <button class="btn" onclick="filterSelection('addidas')"> Addidas</button>
  <button class="btn" onclick="filterSelection('nike')"> Nike</button>
  <button class="btn" onclick="filterSelection('puma')"> Puma</button>
</div>

<!-- Portfolio Gallery Grid -->
<div class="row">
  <div class="column addidas">
    <div class="content">
      <img src="https://assets.adidas.com/images/w_600,f_auto,q_auto/69721f2e7c934d909168a80e00818569_9366/Stan_Smith_Shoes_White_M20324_01_standard.jpg" alt="Addidas" style="width:100%">
      <h4>Model Zero</h4>
      <p>Lorem ipsum dolor..</p>
    </div>
  </div>
  <div class="column addidas">
    <div class="content">
      <img src="https://www.adidas.co.nz/dis/dw/image/v2/aagl_prd/on/demandware.static/-/Sites-adidas-products/default/dw5dae7545/zoom/CQ2624_01_standard.jpg?sh=600&strip=false" alt="Addidas" style="width:100%">
      <h4>Model One</h4>
      <p>Lorem ipsum dolor..</p>
    </div>
  </div>
  <div class="column addidas">
    <div class="content">
      <img src="https://assets.adidas.com/images/w_600,f_auto,q_auto/ab12ced1d0a14151b88ea7fa00ee94a1_9366/Superstar_Foundation_Shoes_Black_B27140_01_standard.jpg" alt="Addidas" style="width:100%">
      <h4>Model Two</h4>
      <p>Lorem ipsum dolor..</p>
    </div>
  </div>

  <div class="column nike">
    <div class="content">
      <img src="https://kickz.akamaized.net/us/media/images/p/600/nike-AIR_FORCE_1_07_PRM_JDI-WHITE_WHITE_BLACK_TOTAL_ORANGE-1.jpg" alt="Nike" style="width:100%">
      <h4>Model Hero</h4>
      <p>Lorem ipsum dolor..</p>
    </div>
  </div>
  <div class="column nike">
    <div class="content">
      <img src="https://kickz.akamaized.net/us/media/images/p/600/nike-AIR_MAX_270_GS-WHITE_DUSTY_CACTUS_BLACK-1.jpg" alt="Nike" style="width:100%">
      <h4>Model XYZ</h4>
      <p>Lorem ipsum dolor..</p>
    </div>
  </div>
  

  <div class="column puma">
    <div class="content">
      <img src="https://images.finishline.com/is/image/FinishLine/19097402_BLK?$Main_gray$" alt="Puma" style="width:100%">
      <h4>Model XYZ</h4>
      <p>Lorem ipsum dolor..</p>
    </div>
  </div>
  
  <div class="column puma">
    <div class="content">
      <img src="https://i.ebayimg.com/images/g/PfkAAOSwE1BbhcWz/s-l640.jpg" alt="Puma" style="width:100%">
      <h4>Puma XS</h4>
      <p>Lorem ipsum dolor..</p>
    </div>
  </div>
<!-- END GRID -->
</div>

Upvotes: 1

Related Questions