ฟังก์ชันการจัดเรียงแบบกำหนดเองใน ng-repeat


113

ฉันมีชุดกระเบื้องที่แสดงจำนวนหนึ่งขึ้นอยู่กับว่าผู้ใช้เลือกตัวเลือกใด ตอนนี้ฉันต้องการจัดเรียงตามตัวเลขที่แสดง

โค้ดด้านล่างแสดงให้เห็นว่าฉันใช้งานได้อย่างไร (โดยการรับ / ตั้งค่าในขอบเขตการ์ดหลัก) ตอนนี้เนื่องจากฟังก์ชัน orderBy ใช้สตริงฉันจึงพยายามตั้งค่าตัวแปรในขอบเขตการ์ดที่เรียกว่า curOptionValue และจัดเรียงตามนั้น แต่ดูเหมือนจะไม่ได้ผล

คำถามจึงกลายเป็นว่าฉันจะสร้างฟังก์ชันการจัดเรียงแบบกำหนดเองได้อย่างไร

<div ng-controller="aggViewport" >
<div class="btn-group" >
    <button ng-click="setOption(opt.name)" ng-repeat="opt in optList" class="btn active">{{opt.name}}</button>
</div>
<div id="container" iso-grid width="500px" height="500px">
    <div ng-repeat="card in cards" class="item {{card.class}}" ng-controller="aggCardController">
        <table width="100%">
            <tr>
                <td align="center">
                    <h4>{{card.name}}</h4>
                </td>
            </tr>
            <tr>
                <td align="center"><h2>{{getOption()}}</h2></td>
            </tr>
        </table>        
    </div>
</div>

และตัวควบคุม:

module.controller('aggViewport',['$scope','$location',function($scope,$location) {
    $scope.cards = [
        {name: card1, values: {opt1: 9, opt2: 10}},
        {name: card1, values: {opt1: 9, opt2: 10}}
    ];

    $scope.option = "opt1";

    $scope.setOption = function(val){
        $scope.option = val;
    }

}]);

module.controller('aggCardController',['$scope',function($scope){
    $scope.getOption = function(){
        return $scope.card.values[$scope.option];
    }
}]);

คำตอบ:


192

จริงๆแล้วorderByตัวกรองสามารถใช้เป็นพารามิเตอร์ไม่เพียง แต่สตริงเท่านั้น แต่ยังเป็นฟังก์ชันด้วย จากorderByเอกสาร: https://docs.angularjs.org/api/ng/filter/orderBy ):

ฟังก์ชัน: ฟังก์ชัน Getter ผลลัพธ์ของฟังก์ชันนี้จะเรียงลำดับโดยใช้ตัวดำเนินการ <, =,>

คุณสามารถเขียนฟังก์ชันของคุณเองได้ ตัวอย่างเช่นหากคุณต้องการเปรียบเทียบไพ่ตามผลรวมของ opt1 และ opt2 (ฉันกำลังสร้างสิ่งนี้ประเด็นคือคุณสามารถมีฟังก์ชันใดก็ได้ตามอำเภอใจ) คุณจะเขียนในคอนโทรลเลอร์ของคุณ:

$scope.myValueFunction = function(card) {
   return card.values.opt1 + card.values.opt2;
};

จากนั้นในเทมเพลตของคุณ:

ng-repeat="card in cards | orderBy:myValueFunction"

นี่คือ jsFiddle ที่ใช้งานได้

สิ่งที่น่าสังเกตอีกประการคือนั่นorderByเป็นเพียงตัวอย่างหนึ่งของตัวกรอง AngularJSดังนั้นหากคุณต้องการพฤติกรรมการสั่งซื้อที่เฉพาะเจาะจงมากคุณสามารถเขียนตัวกรองของคุณเองได้ (แม้ว่าorderByควรจะเพียงพอสำหรับกรณีการใช้งานส่วนใหญ่)


เป็นเรื่องดี แต่เป็นไปได้ไหมที่จะสร้างตัวกรองสำหรับสิ่งนั้นด้วย
hugo der hungrige

ใช่มันยังใช้งานได้ นี่คือเวอร์ชันอัปเดต
jahller

ทำไมไม่มีคำอธิบายเกี่ยวกับพารามิเตอร์หลายตัวในเอกสาร ?? BTW: ขอบคุณมันใช้งานได้ :)
mayankcpdixit

คุณรู้หรือไม่ว่าฉันจะจัดการหลายเกณฑ์ด้วยวิธีนี้ได้อย่างไร ฉันจะคืนค่าหลายค่าจาก myValueFunction ได้อย่างไร
akcasoy

26

โซลูชันที่ยอมรับจะใช้ได้เฉพาะกับอาร์เรย์เท่านั้น แต่ไม่ใช่อ็อบเจ็กต์หรืออาร์เรย์ที่เชื่อมโยงกัน น่าเสียดายเนื่องจาก Angular ขึ้นอยู่กับการใช้งาน JavaScript ของการแจงนับอาร์เรย์จึงไม่สามารถควบคุมลำดับคุณสมบัติของวัตถุได้อย่างสม่ำเสมอ เบราว์เซอร์บางตัวอาจวนซ้ำผ่านคุณสมบัติของวัตถุตามศัพท์ แต่ไม่สามารถรับประกันได้

เช่นได้รับมอบหมายดังต่อไปนี้:

$scope.cards = {
  "card2": {
    values: {
      opt1: 9,
      opt2: 12
    }
  },
  "card1": {
    values: {
      opt1: 9,
      opt2: 11
    }
  }
};

และคำสั่ง<ul ng-repeat="(key, card) in cards | orderBy:myValueFunction">ng-repeat อาจวนซ้ำบน "card1" ก่อนหน้า "card2" โดยไม่คำนึงถึงลำดับการจัดเรียง

ในการแก้ปัญหานี้เราสามารถสร้างตัวกรองที่กำหนดเองเพื่อแปลงวัตถุเป็นอาร์เรย์จากนั้นใช้ฟังก์ชันการจัดเรียงแบบกำหนดเองก่อนที่จะส่งคืนคอลเล็กชัน

myApp.filter('orderByValue', function () {
  // custom value function for sorting
  function myValueFunction(card) {
    return card.values.opt1 + card.values.opt2;
  }

  return function (obj) {
    var array = [];
    Object.keys(obj).forEach(function (key) {
      // inject key into each object so we can refer to it from the template
      obj[key].name = key;
      array.push(obj[key]);
    });
    // apply a custom sorting function
    array.sort(function (a, b) {
      return myValueFunction(b) - myValueFunction(a);
    });
    return array;
  };
});

เราไม่สามารถทำซ้ำการจับคู่ (คีย์ค่า) ร่วมกับตัวกรองแบบกำหนดเองได้ (เนื่องจากคีย์สำหรับอาร์เรย์เป็นดัชนีตัวเลข) ดังนั้นควรอัปเดตเทมเพลตเพื่ออ้างอิงชื่อคีย์ที่แทรก

<ul ng-repeat="card in cards | orderByValue">
    <li>{{card.name}} {{value(card)}}</li>
</ul>

นี่คือซอที่ใช้งานได้โดยใช้ตัวกรองที่กำหนดเองในอาร์เรย์ที่เชื่อมโยง: http://jsfiddle.net/av1mLpqx/1/

อ้างอิง: https://github.com/angular/angular.js/issues/1286#issuecomment-22193332


1
ฉันรู้ว่าฉันไม่ควร แต่ต้องทำ - ขอบคุณ
Elia Weiss

7

ลิงค์ต่อไปนี้อธิบายตัวกรองใน Angular ได้เป็นอย่างดี มันแสดงให้เห็นว่ามันเป็นไปได้อย่างไรในการกำหนดตรรกะการเรียงลำดับแบบกำหนดเองภายใน ng-repeat http://toddmotto.com/everything-about-custom-filters-in-angular-js

สำหรับการเรียงลำดับออบเจ็กต์ที่มีคุณสมบัตินี่คือรหัสที่ฉันใช้: (โปรดทราบว่าการเรียงลำดับนี้เป็นวิธีการจัดเรียง JavaScript มาตรฐานและไม่เฉพาะเจาะจงกับเชิงมุม) Column Name คือชื่อของคุณสมบัติที่จะทำการเรียงลำดับ

self.myArray.sort(function(itemA, itemB) {
    if (self.sortOrder === "ASC") {
        return itemA[columnName] > itemB[columnName];
    } else {
        return itemA[columnName] < itemB[columnName];
    }
});

0

ในการรวมทิศทางพร้อมกับฟังก์ชัน orderBy:

ng-repeat="card in cards | orderBy:myOrderbyFunction():defaultSortDirection"

ที่ไหน

defaultSortDirection = 0; // 0 = Ascending, 1 = Descending

เพียงแค่ผ่านความคิดฉันสังเกตว่าคุณเขียน myOrderbyFunction()แทนคุณจะเขียนmyOrderbyFunctionโดยไม่มี()มันจะถูกเรียกใช้สำหรับองค์ประกอบสองคู่แต่ละคู่เพื่อให้คุณจัดเรียงแบบกำหนดเอง
วิกเตอร์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.