Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS sorting rows by table header

I have four table headers:

$scope.headers = ["Header1", "Header2", "Header3", "Header4"];

And I want to be able to sort my table by clicking on the header.

So if my table looks like this

H1 | H2 | H3 | H4
A    H    D   etc....
B    G    C
C    F    B
D    E    A

and I click on

H2

my table now looks like this:

H1 | H2 | H3 | H4
D    E    A   etc....
C    F    B
B    G    C
A    H    D

That is, the content of each column never changes, but by clicking on the header I want to order the columns by, the rows will reorder themselves.

The content of my table is created by a database call done with Mojolicious and is returned to the browser with

$scope.results = angular.fromJson(data); // This works for me so far

The rest of the code I have cobbled together looks something like this:

<table class= "table table-striped table-hover">
    <th ng-repeat= "header in headers">
        <a> {{headers[$index]}} </a>
    </th>
    <tr ng-repeat "result in results">
        <td> {{results.h1}} </td>
        <td> {{results.h2}} </td>
        <td> {{results.h3}} </td>
        <td> {{results.h4}} </td>
    </tr>
</table>

How do I order the columns from this point, just by clicking on the header at the top of the table?

like image 389
Zack Avatar asked Oct 01 '13 18:10

Zack


3 Answers

I think this working CodePen example that I created will show you exactly how to do what you want.

The template:

<section ng-app="app" ng-controller="MainCtrl">
  <span class="label">Ordered By: {{orderByField}}, Reverse Sort: {{reverseSort}}</span><br><br>
  <table class="table table-bordered">
    <thead>
      <tr>
        <th>
          <a href="#" ng-click="orderByField='firstName'; reverseSort = !reverseSort">
          First Name <span ng-show="orderByField == 'firstName'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
          </a>
        </th>
        <th>
          <a href="#" ng-click="orderByField='lastName'; reverseSort = !reverseSort">
            Last Name <span ng-show="orderByField == 'lastName'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
          </a>
        </th>
        <th>
          <a href="#" ng-click="orderByField='age'; reverseSort = !reverseSort">
          Age <span ng-show="orderByField == 'age'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
          </a>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr ng-repeat="emp in data.employees|orderBy:orderByField:reverseSort">
        <td>{{emp.firstName}}</td>
        <td>{{emp.lastName}}</td>
        <td>{{emp.age}}</td>
      </tr>
    </tbody>
  </table>
</section>

The JavaScript code:

var app = angular.module('app', []);

app.controller('MainCtrl', function($scope) {
  $scope.orderByField = 'firstName';
  $scope.reverseSort = false;

  $scope.data = {
    employees: [{
      firstName: 'John',
      lastName: 'Doe',
      age: 30
    },{
      firstName: 'Frank',
      lastName: 'Burns',
      age: 54
    },{
      firstName: 'Sue',
      lastName: 'Banter',
      age: 21
    }]
  };
});
like image 130
Adam Avatar answered Oct 19 '22 04:10

Adam


Here is a fiddle that can help you to do this with AngularJS
http://jsfiddle.net/patxy/D2FsZ/

<th ng:repeat="(i,th) in head" ng:class="selectedCls(i)" ng:click="changeSorting(i)">
     {{th}}
</th>

Then something like this for your data:

<tr ng:repeat="row in body.$orderBy(sort.column, sort.descending)">
    <td>{{row.a}}</td>
    <td>{{row.b}}</td>
    <td>{{row.c}}</td>
</tr>

With such functions in your AngularJS controller:

scope.sort = {
    column: 'b',
    descending: false
};

scope.selectedCls = function(column) {
    return column == scope.sort.column && 'sort-' + scope.sort.descending;
};

scope.changeSorting = function(column) {
    var sort = scope.sort;
    if (sort.column == column) {
        sort.descending = !sort.descending;
    } else {
        sort.column = column;
        sort.descending = false;
    }
};
like image 30
Deblaton Jean-Philippe Avatar answered Oct 19 '22 02:10

Deblaton Jean-Philippe


Another way to do this in AngularJS is to use a Grid.

The advantage with grids is that the row sorting behavior you are looking for is included by default.

The functionality is well encapsulated. You don't need to add ng-click attributes, or use scope variables to maintain state:

    <body ng-controller="MyCtrl">
        <div class="gridStyle" ng-grid="gridOptions"></div>
    </body>

You just add the grid options to your controller:

  $scope.gridOptions = {
    data: 'myData.employees',
    columnDefs: [{
      field: 'firstName',
      displayName: 'First Name'
    }, {
      field: 'lastName',
      displayName: 'Last Name'
    }, {
      field: 'age',
      displayName: 'Age'
    }]
  };

Full working snippet attached:

var app = angular.module('myApp', ['ngGrid', 'ngAnimate']);
app.controller('MyCtrl', function($scope) {

  $scope.myData = {
    employees: [{
      firstName: 'John',
      lastName: 'Doe',
      age: 30
    }, {
      firstName: 'Frank',
      lastName: 'Burns',
      age: 54
    }, {
      firstName: 'Sue',
      lastName: 'Banter',
      age: 21
    }]
  };

  $scope.gridOptions = {
    data: 'myData.employees',
    columnDefs: [{
      field: 'firstName',
      displayName: 'First Name'
    }, {
      field: 'lastName',
      displayName: 'Last Name'
    }, {
      field: 'age',
      displayName: 'Age'
    }]
  };
});
/*style.css*/
.gridStyle {
    border: 1px solid rgb(212,212,212);
    width: 400px;
    height: 200px
}
<!DOCTYPE html>
<html ng-app="myApp">
    <head lang="en">
        <meta charset="utf-8">
        <title>Custom Plunker</title>
        <link rel="stylesheet" type="text/css" href="http://angular-ui.github.com/ng-grid/css/ng-grid.css" />
        <link rel="stylesheet" type="text/css" href="style.css" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular-animate.js"></script>
        <script type="text/javascript" src="http://angular-ui.github.com/ng-grid/lib/ng-grid.debug.js"></script>
        <script type="text/javascript" src="main.js"></script>
    </head>
    <body ng-controller="MyCtrl">
        <div class="gridStyle" ng-grid="gridOptions"></div>
    </body>
</html>
like image 27
David Rinck Avatar answered Oct 19 '22 04:10

David Rinck