Search code examples
javascriptsortingcolumnsorting

Create a generic sortableTable object to be used to alphabetically sort a table elements each time a column is clicked using only JavaScript


I'm working on project which don't use jQuery but only JavaScript and we have a need to sort alphabetically ascending a table values (without any external library).

The objective is to sort rows elements each time a column (th element) is clicked.

Example

If I have this table

enter image description here

When I click on "Names", the table should be refreshed like that:

enter image description here

When I click on "Tel", the table should be refreshed like that:

enter image description here


Solution

  • I'm sharing my own solution here. If you have any remark or suggestions, please share.

    I'm updating my solution by adding an inverse order feature:

    • When you first click on Names for example, the table will be refreshed with an ascending order of names.
    • When you click a 2nd time on Names, the table will be refreshed with a descending order of names.
    • When you click a 3rd time on Names, the table will be refreshed with an ascending order of names.
    • etc...

    var sortableTable = {
    	/**
    	* The table to sort
    	*/
    	table: null,
    	getTable: function(){
    		return this.table;
    	},
    	setTable: function(table){
    		this.table = table;
    	},
    	/**
    	* The column used for sorting
    	*/	
    	element: null,
    	getElement: function(){
    		return this.element;
    	},
    	setElement: function(element){
    		this.element = element;
    	},
        /**
        * When ooderDirection is 1 => Ascending order 
        * When ooderDirection is -1 => Descending order 
        */
    	orderDirection: 1,
    	getOrderDirection: function(){
    		return this.orderDirection;
    	},
    	setOrderDirection: function(orderDirection){
    		this.orderDirection = orderDirection;
    	},
    	/**
    	* Get table rows elements
    	*/		
    	getRows: function(){
    		var rows = [];
    		if(null !== this.getTable()){
    			var allRows = this.getTable().rows;
    			/*
    				When I returned allRows directly, 
    				in the sort function when I do: rows.sort();
    				it display an error: Uncaught TypeError: rows.sort is not a function
    				So I'm converting this object to an array
    			*/
    			var arrayRows = [];
    			//allRows contains all rows with <th> elements, 
    			//so I'm removing th elements (index 0)
    			for(let i=1 ; i<allRows.length ; i++){
    				arrayRows.push(allRows[i]);
    			}
    			return (arrayRows);
    		}
    		return null;
    	},
    	/**
    	* Display rows using the sort result
    	*/		
    	refresh: function(rows){
    		for(let i=0 ; i<rows.length ; i++){
    			this.getTable().appendChild(rows[i]);
    		}
    	},
    	/**
    	* Sort alphabetically (ASC)
    	*/		
    	sort: function(indexOfClickedTh){
    		var rows = this.getRows();
            var that = this;
    		rows.sort(function(item1, item2){
    			var contentItem1 = item1.getElementsByTagName('td')[indexOfClickedTh].innerText;
    			var contentItem2 = item2.getElementsByTagName('td')[indexOfClickedTh].innerText;
    			let resultCompare = contentItem1.localeCompare(contentItem2);
                resultCompare = resultCompare * that.getOrderDirection();
    			//console.info('comparing(' + contentItem1 + ', ' + contentItem2 + ')=' + resultCompare);	
    			return resultCompare;
    		});
    		this.refresh(rows);
    	}
    }
    
    
    //The first click will generate an ascending sort
    var initialOderDirection = -1;
    
    var myTableToSort = document.getElementById('users');
    sortableTable.setTable(myTableToSort);
    sortableTable.setOrderDirection(initialOderDirection);
    var ListOfTh = document.getElementById('users').getElementsByTagName('th');
    for(var i=0 ; i<ListOfTh.length ; i++){
    	var oneTh = ListOfTh[i];
    	oneTh.addEventListener("click", function(){
            //console.info("------> New sort based on '" + this.innerText + "' <------");
          
            // Set the current clicked <th> element
    		sortableTable.setElement(this);
          
            //Inverse the order
            sortableTable.setOrderDirection( sortableTable.getOrderDirection() * -1 );
            
            //Do the sort and refresh table result
    		sortableTable.sort(this.cellIndex);	
    	});
    };
    table{
        font-size: 16px;
        border-collapse: collapse;
        border-spacing: 0;
        width: 100%;
    }
    table th{
        padding-top: 11px;
        padding-bottom: 11px;
        background-color: #6295a5;
        color: white;
    }
    table td{
        border: 1px solid #ddd;
        text-align: left;
        padding: 8px;
    }
    table tr:nth-child(even) {
        background-color: #f2f2f2;
    }
    table th{
    	cursor: pointer;
    }
    table th:hover{
    	color: #dea82e;
    	background-color: #37545d;
    }
    <table id="users">
    	<thead>
    		<tr>
    			<th>Names</th>
    			<th>Functions</th>
    			<th>Emails</th>
    			<th>Tel</th>
    		</tr>
    	</thead>
    	<tbody>
    		<tr>
    			<td>xMxxx</td>
    			<td>Physicists</td>
    			<td>xmxxx@domain.com</td>
    			<td>00 55 99 99 99</td>
    		</tr>
    		<tr>
    			<td>xJxxx</td>
    			<td>Air Traffic Controllers</td>
    			<td>xjxxx@domain.com</td>
    			<td>00 22 99 99 99</td>
    		</tr>
    		<tr>
    			<td>xExxx</td>
    			<td>Engineer</td>
    			<td>xexxx@domain.com</td>
    			<td>00 33 99 99 99</td>
    		</tr>
    		<tr>
    			<td>xAxxx</td>
    			<td>Mechanical engineer</td>
    			<td>xaxxx@domain.com</td>
    			<td>00 11 99 99 99</td>
    		</tr>
    		<tr>
    			<td>xZxxx</td>
    			<td>Doctor</td>
    			<td>xzxxx@domain.com</td>
    			<td>00 44 99 99 99</td>
    		</tr>
    		<tr>
    			<td>xPxxx</td>
    			<td>Professor</td>
    			<td>xpxxx@domain.com</td>
    			<td>00 66 99 99 99</td>
    		</tr>
    	</tbody>
    </table>