Sorting rows by words and numbers in JavaScript explained

Hello, I'm a beginner and I need help sorting the table rows in the following table. I also want to attach an onclick listener to the header after it is displayed.

ID Name Inventory Volume
1 Rachel Data is not enough
2 Ross 100
3 Monica 1
4 Connor Data is not enough
5 Dustin -5

I would like to sort this table with the words at the end in descending order.

ID Name Inventory Volume
2 Ross 100
3 Monica 10
5 Dustin -5
1 Rachel Data is not enough
4 Connor Data is not enough

In addition, I'd like the other columns to be sorted as well and have the function to sort them too.

I tried a solution but it only works for one column. Here is the link to my code: https://jsfiddle.net/7wnke5q2/

function sortData(data, method) {
  let lessData = 'Data Not Enough'
  let lastItems = []
  let sortedList;
  if (method == 'descending') {
    sortedList = data.sort((a, b) => {
      return a - b
    })
  } else if (method == 'ascending') {
    sortedList = data.sort((a, b) => {
      return b - a
    })
  }
  for (let i = 0; i < sortedList.length; i++) {
    if (sortedList[i] == lessData) {
      let item = sortedList[i]
      sortedList.splice(i, 1)
      sortedList.push(item)
    }
  }
  sortedList = sortedList.concat(lastItems)
  return sortedList
}

I would really appreciate your help. Thank you!

Answer №1

If my understanding is correct, you are looking to have all instances of "Data Not Enough" at the end of the sorted list. Here is a function that can achieve this:

function sortData(data, method) {
    let lessData = 'Data Not Enough'
    let sortedList;  
    sortedList = data.sort((a, b) => {
        if(a=='Data Not Enough')
            return 1
        if(b=='Data Not Enough')
            return -1
      return method=='ascending'? a-b : b-a
      })
    return sortedList
}

Answer №2

Is that similar to what you were looking for?
Simply click on the header columns to organize the table

const 
  myTableHead     = document.querySelector('#my-table thead')
, myTableHead_TH  = document.querySelectorAll('#my-table thead th')
, myTableBody     = document.querySelector('#my-table tbody')
, myTableBody_TR  = [...document.querySelectorAll('#my-table tbody tr')]
, sortOrder       = ['','asc','desc']
, isDNE = str => str.trim() === 'Data is not enough'
  ;
myTableHead.onclick = ({target}) =>
  {
  if (!target.matches('th')) return
  let idx = (sortOrder.findIndex(x=>x===target.className) +1) %3
  myTableHead_TH.forEach(th=>th.className='')
  target.className = sortOrder[idx]

  if ( sortOrder[idx] )
    {
    myTableBody_TR
      .sort(dynaSort(target.cellIndex, target.dataset.type, sortOrder[idx] ))
      .forEach(tr=>myTableBody.appendChild(tr) )
    }
  }

function dynaSort( colIndex, colType, order='asc' )
  {
  let sortOrder = (order === 'desc') ? -1 : 1
 
  return function(row_a,row_b)
    {
    let a = row_a.cells[colIndex].textContent
      , b = row_b.cells[colIndex].textContent
      ;
    if (isDNE(a) && isDNE(b)) return 0
    if (isDNE(a))  return +1
    if (isDNE(b)) return -1

    if (colType==='str')  return (a.trim().localeCompare(b.trim())) *sortOrder 
    return (Number(a) - Number(b)) *sortOrder 
    }
  }
table  {
  border-collapse : collapse;
  margin          : 2em 1em;
  font-family: Arial, Helvetica, sans-serif;
  }
td,th  {
  padding    : .2em .8em;
  border     : 1px solid darkblue;
  }
th::after {
  display    :  block;
  float      : inline-end;
  content    : '\25B7';
  margin     : 0 0 0 1em;
  transition : 180ms;
  color      : transparent;
}
th.asc::after {
  transform  : rotate(-90deg);
  color      : whitesmoke;
}
th.desc::after {
  transform  : rotate(+90deg);
  color      : whitesmoke;
}
thead {
  background : #437c97;
  color      : whitesmoke;
  cursor     : pointer;
  }
<table id="my-table" >
  <thead>
    <tr>
      <th data-type="num">ID</th> 
      <th data-type="str">Name</th>  
      <th data-type="num">Inventory Volume</th>  
    </tr>
  </thead>
  <tbody>
    <tr> <td>1</td> <td>Rachel</td> <td>Data is not enough</td> </tr>
    <tr> <td>2</td> <td>Ross</td>   <td>  100 </td>             </tr>
    <tr> <td>3</td> <td>Monica</td> <td>    1 </td>             </tr>
    <tr> <td>4</td> <td>Connor</td> <td>Data is not enough</td> </tr>
    <tr> <td>5</td> <td>Dustin</td> <td>   -5 </td>             </tr>
  </tbody>
</table>

Answer №3

  • This should work perfectly! Utilizing the @YamirL sorting algorithm.
function sort(e, method) {
  //Get table
  while ((e = e.parentElement) && !e.classList.contains("table"));
  //Get rows
  let rows = Array.from(e.getElementsByTagName("tr"));
  //Get each value for each row
  let values = rows.map(row => {
    let tds = Array.from(row.getElementsByTagName("td"));
    return tds.map(td => td.innerHTML);
  });
  
  // Remove headers from values array
  values.shift();

  // Sort the array by volume
  values.sort((a, b) => {
    var exception = "Data Not Enough";
    if(a[1] == exception)
      return 1;
    if(b[1] == exception)
      return -1;
    return method == 'ascending' ? a[1] - b[1] : b[1] - a[1];
  });

  // Put sorted values back on the table

  // Get body
  let body = e.getElementsByTagName("tbody")[0];
  // Erase Body
  body.innerHTML = "";
  // Iterate each row
  values.forEach(row => {
    // Create new row element
    let tr = document.createElement("tr");
    // Iterate each column
    row.forEach(val => {
      // Create new value
      let td = document.createElement("td");
      // Append values
      td.append(val);
      tr.append(td);
    });
    // Append row to body
    body.append(tr);
  });
}

Here is a snippet to test the complete code, I included a <tbody> in the table.

function sort(e, method) {
  while ((e = e.parentElement) && !e.classList.contains("table"));
  let rows = Array.from(e.getElementsByTagName("tr"));
  let values = rows.map(row => {
    let tds = Array.from(row.getElementsByTagName("td"));
    return tds.map(td => td.innerHTML);
  });

  values.shift(); 

  values.sort((a, b) => {
    var exception = "Data Not Enough";
    if(a[1] == exception)
      return 1;
    if(b[1] == exception)
      return -1;
    return method == 'ascending' ? a[1] - b[1] : b[1] - a[1];
  });

  
  let body = e.getElementsByTagName("tbody")[0];
  body.innerHTML = "";
  values.forEach(row => {
    let tr = document.createElement("tr");
    row.forEach(val => {
      let td = document.createElement("td");
      td.append(val);
      tr.append(td);
    });
    body.append(tr);
  });
}
.clickable {
  cursor: pointer;
}

.clickable:hover {
  opacity: 0.7;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>


<table class="table">
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col" class="clickable" onclick='sort(this, "descending")'>Volume</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Joey</td>
      <td>Data Not Enough</td>
    </tr>
    <tr>
      <td>Ross</td>
      <td>-5</td>
    </tr>
    <tr>
      <td>Monica</td>
      <td>1</td>
    </tr>
    <tr>
      <td>Ben</td>
      <td>100</td>
    </tr>
    <tr>
      <td>Chandler</td>
      <td>Data Not Enough</td>
    </tr>
  </tbody>
</table>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Prevent the layout from shifting with CSS

I am faced with a challenge regarding a grid of images that are dynamically generated on the screen. The number of images in each row of the grid is dependent on the size of the page. While everything functions properly when the page is at a certain size, ...

What could be causing this Form to redirect to the incorrect file path?

I recently updated the login menu for my Admin panel. Initially, the login page was named login.php, but I decided to change it to index.php. Even though I made sure to update the action from login.php to index.php, when I click on the login button it st ...

The functionality of the click event attached with the addEventListener is

I have a unique project where I am developing a user interface for a paper-rock-scissor game. To create the UI, I included four buttons: "Start game," "rock," "paper," and "scissor." Initially, I wrote separate code for each button, which worked perfectly ...

Material UI Input Field, Present Cursor Location

Is there a way to retrieve the current cursor (caret) position in a MaterialUI text field? https://material-ui.com/components/text-fields/ I am looking to make changes to the string content at a specific index, such as inserting a character X between cha ...

The struggle between Node.js 404 errors and Angular's URL refresh issue

I am currently developing a Node.js and AngularJS application. I encountered an issue where a page loads successfully when the URL is entered, but then I added a script to redirect to a 404 error page. Now, only one of the criteria works at a time - either ...

Transform a <td> into a table-row (<tr>) nested within a parent <tr> inside an umbrella structure

Similar questions have been asked in the past, but I still haven't found a solution to my specific inquiry. Here it is: I have a table that needs to be sortable using a JavaScript plugin like ListJS. The key requirement is that I must have only one & ...

Automatically Assigning a Default Value to a Column Using SEQUELIZE ORM

When fetching data from a database using Sequelize ORM, I need to set a default value. Here is an example of the SQL query: SELECT a.affiliate_id, a.active AS current_state, IF(MAX(cn.contract_id) IS NULL ,0, IF(DATEDIFF(NOW(),MAX(cn.contract_date) ...

Error: The combination of 0 and .... is invalid and cannot be used as a function

I am currently in the process of developing a next.js application using Material-ui. I have been attempting to integrate material-ui into my project. Following guidance from the official GitHub page, I have copied the _app.js , _document.js , theme.js fil ...

Show the value in the input text field if the variable is present, or else show the placeholder text

Is there a ternary operator in Angular 1.2.19 for templates that allows displaying a variable as an input value if it exists, otherwise display the placeholder? Something like this: <input type="text "{{ if phoneNumber ? "value='{{phoneNumber}}&a ...

Is it advisable to compress my API response in PHP?

At this stage, I find myself needing to generate extensive reports in order to gain a better understanding of the data at hand. To do so, I must retrieve one of my tables which contains around 50 parameters and 40,000 rows. While fetching the data via API ...

Validating forms using TypeScript in a Vue.js application with the Vuetify

Currently, I am attempting to utilize Vue.js in conjunction with TypeScript. My goal is to create a basic form with some validation but I keep encountering errors within Visual Studio Code. The initial errors stem from my validate function: validate(): v ...

The Bootstrap navigation bar isn't displaying properly on mobile devices

Help! My Bootstrap navbar is not working properly on mobile view. The menu icon shows up but when clicked, no items are displayed. Here is the HTML code for my navbar: <header class="header_area"> <div class="main-menu"> ...

Using Angular 4 to delete selected rows based on user input in typescript

I am facing a challenge with a table that contains rows and checkboxes. There is one main checkbox in the header along with multiple checkboxes for each row. I am now searching for a function that can delete rows from the table when a delete button is clic ...

PHP Instant Chat Improvements

I am in the process of developing a messaging system that consists of the following components: A form that allows users to send messages, with PHP handling the insertion of data into a MySQL Table named userMessages upon submission. A PHP page that ...

Having trouble getting the jQuery click event to work on iPhone browsers? Despite already trying the cursor:pointer; method

I am facing an issue with setting a click event on anchor tags in my WordPress site. Surprisingly, the event works perfectly fine on all of my devices including PC, Android phone, and tablet except for my iPhone. Despite trying to set the 'Cursor&apo ...

Combining ASP.NET MVC with HTML5 for dynamic web development

We are in the process of planning a new project and are interested in utilizing ASP.NET with the MVC pattern. Additionally, we want to incorporate the new features of HTML5. However, we have been having trouble finding sufficient information or connecting ...

Inserting multiple rows of data into a MySQL database in a single page using only one query in PHP

This snippet shows a MySQL query being used to update and insert data into a database: if ($_POST["ok"] == "OK") { $updateSQL = sprintf("UPDATE attend SET at_status=%s, at_remarks=%s WHERE at_tt_idx=%s", GetSQLValueString ...

Height of border not being displayed accurately

I have been searching for a solution to my unique issue with inserting borders in HTML and CSS. When I try to add a border to three images, the height does not display correctly. This is all part of my learning process to improve my skills in coding. Belo ...

Using JavaScript with namespaces in C#

I am currently trying to explore AJAX and web services through self-teaching using C# and JavaScript. After doing some research on Google, it seems like I might be facing a namespace problem. Here is the snippet of my code: using System; using System.Col ...

Can you explain the distinction between querying a database and making a request to an endpoint?

Recently, I've been diving into learning mongoose but came across a code that left me puzzled. I'm curious as to why we include the async keyword at the beginning of the callback function when querying a database. Isn't it already asynchron ...