使用AngularJs的可排序表列

时间:2013-09-13 15:26:07

标签: angularjs angularjs-ng-repeat

我正在尝试对从JSON源填充的数据表进行排序。我的代码如下:

HTML:

<div ng-app="myApp">
    <div ng-controller="PurchasesCtrl">
        <table cellspacing="0">
            <tr class="first">
                <th class="first" ng:click="changeSorting(purchases.date)">Date</th>
                <th ng:click="changeSorting(purchases.text)">Description</th>
                <th ng:click="changeSorting(purchases.price)">Amount</th>
                <th ng:click="changeSorting(purchases.availability)">Status</th>
            </tr>
            <tr ng-repeat="purchase in purchases.data">
                <td class="first">{{purchase.date}}</td>
                <td>{{purchase.text}}</td>
                <td>{{purchase.price}}</td>
                <td>{{purchase.availability}}</td>
            </tr>
        </table>
    </div>
</div>

JS:

var myApp = angular.module("myApp",[]);

myApp.factory("Purchases", function(){
    var Purchases = {};

    Purchases.data = [
        {
            date: "10/05/2012",
            text: "1 Lorem ipsum dolor sit amet ipsum dolor",
            price: "£123.45",
            availability: "1 Available until 10th Dec 2013"
        },
        {
            date: "24/05/2012",
            text: "2 Lorem ipsum dolor sit amet ipsum dolor",
            price: "£234.56",
            availability: "2 Available until 10th Dec 2013"
        },
        {
            date: "20/05/2012",
            text: "3 Lorem ipsum dolor sit amet ipsum dolor",
            price: "£345.67",
            availability: "3 Available until 10th Dec 2013"
        }
    ];
    return Purchases;
});

function PurchasesCtrl($scope, Purchases){
    $scope.purchases = Purchases;

    $scope.changeSorting = function(column) {
        var sort = $scope.sort;

        if (sort.column == column) {
            sort.descending = !sort.descending;
        } else {
            sort.column = column;
            sort.descending = false;
        }
    };
}

小提琴:http://jsfiddle.net/7czsM/1/

正如您所看到的,我已经尝试在表标题中添加一个click函数来调用一个对数据进行排序的函数,但它不起作用。

我已经看到了一个这样的事情的例子,在这里:http://jsfiddle.net/vojtajina/js64b/14/,但是当我尝试将相同类型的东西应用到我的场景时,它会很快崩溃;例如,我尝试通过添加以下内容以编程方式在JSON中添加表头:

var Purchases = {};

Purchases.head = [
        {
            date: "Date",
            text: "Text column",
            price: "Price column",
            availability: "Availability column"
        }

    Purchases.data = [
        {
            date: "10/05/2012",
            text: "1 Lorem ipsum dolor sit amet ipsum dolor",
            price: "£123.45",
            availability: "1 Available until 10th Dec 2013"
        },

这只会阻止任何工作,但我认为可以将多组数据添加到Angular变量中?

我是Angular的新手,所以我真的很喜欢这个。任何指针都会非常感激,谢谢。

5 个答案:

答案 0 :(得分:25)

更新了jsfiddle:http://jsfiddle.net/gweur/

sza是对的,你确实忘记了$ scope.sort对象,但是你也错过了ng-repeat中的orderBy过滤器

|orderBy:sort.column:sort.descending

此外,您需要将列名显式传递给changeSorting()函数,例如

ng-click="changeSorting('text')"  

不确定是否有不同的方法可以解决这个问题。

最后,ng-click是您正在使用的AngularJS版本的正确语法。

答案 1 :(得分:7)

制作表格可排序的另一个非常好的例子

http://jsfiddle.net/vojtajina/js64b/14/

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

scope.changeSorting = function(column) {
    var sort = scope.sort;
    if (sort.column == column) {
        sort.descending = !sort.descending;
    } else {
        sort.column = column;
        sort.descending = false;
    }
};

答案 2 :(得分:5)

这是我的解决方案。我还将整个事情包装成一个指令。唯一的依赖是UI.Bootstrap.pagination,它在分页方面做得很好。

以下是plunker

以下是github source code.

答案 3 :(得分:0)

或者你可以使用#ngTasty作为简单的表指令。 github:https://github.com/Zizzamia/ng-tasty docs:http://zizzamia.com/ng-tasty/directive/table

答案 4 :(得分:0)

我认为您的AngularJS样板代码,特别是设置Controller和Factory的代码可能存在语法错误。

这是数据工作的示例,并在表列排序方法上进行了扩展。由于AngularJS擅长处理javascript数据结构以在HTML中显示,因此您可以重新排列内存中的javascript数组,而AngularJS会进行更改。 此示例允许单击表的标题,这将触发基于该列数据类型的排序。如果已在该列上对其进行了排序,则它将对该列进行反向排序。类型检测是通过提供的isNumeric()函数和一个两个小小的调整来完成的:

  1. 已添加检查是否以“#”符号作为标题输入,并在toggleSort方法中将其排序为数字。如果需要,用户可以轻松删除。
  2. 当toggleSort尝试按字母顺序排序时,如果捕获到TypeError,则切换为按数字排序。

var myApp = angular.module("myApp", []);

myApp.factory("Purchases", function() {
  var Purchases = {};

  Purchases.data = [{
    date: "10/05/2012",
    text: "1 Lorem ipsum dolor sit amet ipsum dolor",
    price: "£123.45",
    availability: "1 Available until 10th Dec 2013"
  }, {
    date: "24/05/2012",
    text: "2 Lorem ipsum dolor sit amet ipsum dolor",
    price: "£234.56",
    availability: "2 Available until 10th Dec 2013"
  }, {
    date: "20/05/2012",
    text: "3 Lorem ipsum dolor sit amet ipsum dolor",
    price: "£345.67",
    availability: "3 Available until 10th Dec 2013"
  }];
  return Purchases;
});

myApp.controller("PurchasesCtrl", function($scope, Purchases) {
  $scope.purchases = Purchases.data;

  // Dynamically get the entry headers to use with displaying the nested data via header-key lookups
  // Assumes all lines contain same key-text data
  $scope.purchasesHeaderKeys = []; // Contains only the key-data, not the values
  for (var key in $scope.purchases[0]) {
    if ($scope.purchases[0].hasOwnProperty(key)) {
      $scope.purchasesHeaderKeys.push(key);
    }
  }


  /**
   * Determine if the input value is a number or not.
   * @param n The input value to be checked for numeric status.
   * @returns true if parameter is numeric, or false otherwise.
   * 
   * This method uses the following evaluations to determine if input is a numeric:
   * 
   * 		(5); // true  
   * 		('123'); // true  
   * 		('123abc'); // false  
   * 		('q345'); // false
   * 		(null); // false
   * 		(""); // false
   *		([]); // false
   * 		('   '); // false
   * 		(true); // false
   * 		(false); // false
   * 		(undefined); // false
   * 		(new String('')); // false
   * 
   * @author C.D. (modified by)
   * @original https://stackoverflow.com/a/1421988/10930451
   * 
   */
  function isNumeric(n) {
    if (!isNaN(parseFloat(n)) && !isNaN(n - 0) && n !== null && n !== "") {
      return true;
    }
    return false;
  }

  /**
   * Column Sort Method (generic). Sort based on target column header or reverse sort if already selected on that.
   * @param dataSource The array of JSON data to be sorted
   * @param headers The array of JSON object-keys (table column headers) to be referenced
   * @param index The target JSON object-key to sort the table columns based upon
   * 
   * @author C.D.
   */
  $scope.lastSortIndex = 0;
  $scope.changeSorting = function(dataSource, headers, index) {
    if ($scope.lastSortIndex === index) {
      dataSource.reverse();
    } else {
      var key = headers[index];
      if (key === "#" || isNumeric(dataSource[key])) { // Compare as numeric or on '#' sign
        dataSource.sort((a, b) => parseFloat(a[key]) - parseFloat(b[key]));
      } else // Compare as Strings
      {
        try { // Attempt to sort as Strings
          dataSource.sort((a, b) => a[key].localeCompare(b[key]));
        } catch (error) {
          if (error.name === 'TypeError') { // Catch type error, actually sort as Numeric
            dataSource.sort((a, b) => parseFloat(a[key]) - parseFloat(b[key]));
          }
        }
      }
      $scope.lastSortIndex = index;
      $scope.reverseSorted = false;
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.13/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<html ng-app="myApp">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  <title>AngularJS - Hello World</title>


  <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">

  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
</head>

<body ng-controller="PurchasesCtrl">
  <div class="container">
    <table class="table table-hover	table-sm">
  		<thead>
  			<tr>
  				<th ng-repeat="header in purchasesHeaderKeys">
  					<a ng-click="changeSorting(purchases, purchasesHeaderKeys, $index)">{{ header }}</a>
  				</th>
  			</tr>
  		</thead>
  
  		<tbody>
  			<!-- Data is nested, so double-repeat to extract and display -->
  			<tr ng-repeat="row in purchases" >
  				<td ng-repeat="key in purchasesHeaderKeys">
  					{{row[key]}}
  				</td>
  			</tr>
  		</tbody>
  	</table>
  </div>
</body>

</html>

我整理了一个Plunker example来进行演示。只需单击标题,它们就会对内存中的数组进行排序,AngularJS将在那里获取更改并刷新DOM的该部分。