Piotr
Piotr

Reputation: 145

How to sort table by asc and desc all field in React js

I am building a simple app in ReactJS that works with a JSON array by calling a certain API. I am then populating the results of the array in a table. I now wanted to make the columns of the table sortable . What I ideally want is to have both ascending and descending sorting. Once I click on the header when it is sorted ascending, it should sort descending and vice-versa.but problem is its working only one time not working like both asc and desc order so how to do to this in both asc and desc. Here is my code.

import React, { Component } from "react";
import "./styles.css";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      driver: []
    };
  }

  async componentDidMount() {
    try {
      const res = await fetch(`https://digitalfleet.eu/api/1/drivers/`);
      const driver = await res.json();
      console.log(driver);
      this.setState({
        driver
      });
    } catch (e) {
      console.log(e);
    }
  }

  compareBy(key) {
    return function (a, b) {
      if (a[key] < b[key]) return -1;
      if (a[key] > b[key]) return 1;
      return 0;
    };
  }

  sortBy(key) {
    let arrayCopy = [...this.state.driver ];
    arrayCopy.sort(this.compareBy(key));
    this.setState({driver: arrayCopy});
  }

  render() {
    const { driver } = this.state;
    return (
      <div className="App">
        <table className="table table-hover">
          <thead>
            <tr className="th ">
              <th style={{ width: "5%" }}>id</th>
              <th>Name</th>
              <th className="">Car</th>
              <th className="" onClick={() => this.sortBy('milage')}>Milage </th>
              <th className="">Fuel Consumed</th>
              <th className="">Average Fuel</th>
              <th className="" onClick={() => this.sortBy('overspeeding_distance')}>Overspeeding Distance</th>
              <th onClick={() => this.sortBy('critical_overspeed')}>Critical Speed</th>
              <th onClick={() => this.sortBy('overallscore')}>Score</th>
            </tr>
          </thead>
          <tbody>
            {/* currPage.data */}
            {driver.map((c, i) => (
              <tr key={c.pk}>
                <td>{i + 1}</td>
                <td style={{ color: "#b71c1c" }} className="font-weight-bolder">
                  {c.name ? `${c.name}` : " ? "}
                  {/* </a> */}
                </td>
                <td>{c.carquanttity ? `${c.carquanttity}` : "-"} </td>
                <td>{c.milage ? `${c.milage.toFixed(1)}` : "-"} </td>
                <td>
                  {c.fuel_consumed ? `${c.fuel_consumed.toFixed(1)}` : "-"}
                </td>
                <td>
                  {c.average_fuel_consumed
                    ? `${c.average_fuel_consumed.toFixed(1)}`
                    : "-"}{" "}
                </td>
                <td>
                  {c.overspeeding_distance
                    ? `${c.overspeeding_distance.toFixed(1)}`
                    : "-"}
                </td>
                <td>
                  {c.critical_overspeed
                    ? `${c.critical_overspeed.toFixed(1)}`
                    : "-"}
                </td>
                <td>
                  {c.overallscore ? `${c.overallscore.toFixed(1)}` : " - "}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    );
  }
}

export default App;

And here is codesanbox link of my code. https://codesandbox.io/s/pensive-mountain-i259j

Upvotes: 1

Views: 9637

Answers (2)

ArielGro
ArielGro

Reputation: 783

You need to add a direction to your compare function, and use it to reverse the results as follows:

compareBy(key, ascending) {
    let reverse = ascending ? 1 : -1;
    return function (a, b) {
      if (a[key] < b[key]) return -1 * reverse;
      if (a[key] > b[key]) return 1 * reverse;
      return 0;
    };
  }

Now, you will have to keep a boolean for each row you want to sort by, and toggle it (turn true to false and vice versa) on each click

<th className="" onClick={() => {this.milageAsc = !this.milageAsc; this.sortBy('milage', this.milageAsc)}}>Milage </th>

The flag can be also used for toggling a class to an arrow sign that indicates the sort order on the column's header...

I might got the Ascending / Descending direction wrong but I hope you catch my drift

Upvotes: 2

user2485861
user2485861

Reputation: 54

You have written same sort functionality for both ascending and desc while it should return different type in both cases.

without maintaining additional flag I fixed it .Check this out Visit https://codesandbox.io/s/pensive-engelbart-i6n2y

Upvotes: 1

Related Questions