AngularJS เรียงลำดับตามคุณสมบัติ


95

สิ่งที่ฉันพยายามทำคือจัดเรียงข้อมูลบางส่วนตามคุณสมบัติ นี่คือตัวอย่างที่ฉันควรจะใช้งานได้ แต่ไม่ได้ผล

ส่วน HTML:

<div ng-app='myApp'>
    <div ng-controller="controller">
    <ul>
        <li ng-repeat="(key, value) in testData | orderBy:'value.order'">
            {{value.order}}. {{key}} -> {{value.name}}
        </li>
    </ul>
    </div>
</div>

ส่วน JS:

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

myApp.controller('controller', ['$scope', function ($scope) {

    $scope.testData = {
        C: {name:"CData", order: 1},
        B: {name:"BData", order: 2},
        A: {name:"AData", order: 3},
    }

}]);

และผลลัพธ์:

  1. A -> AData
  2. B -> BData
  3. C -> CData

... IMHO นั้นควรมีลักษณะดังนี้:

  1. C -> CData
  2. B -> BData
  3. A -> AData

ฉันพลาดอะไรไป (นี่คือJSFiddleพร้อมสำหรับการทดลอง) หรือไม่

คำตอบ:


148

ตัวกรอง orderBy ของ AngularJS รองรับอาร์เรย์ - ไม่มีวัตถุ ดังนั้นคุณต้องเขียนตัวกรองขนาดเล็กของตัวเองซึ่งจะจัดเรียงให้คุณ

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

นี่คือตัวกรองorderObjectByของฉันสำหรับ AngularJS:

app.filter('orderObjectBy', function(){
 return function(input, attribute) {
    if (!angular.isObject(input)) return input;

    var array = [];
    for(var objectKey in input) {
        array.push(input[objectKey]);
    }

    array.sort(function(a, b){
        a = parseInt(a[attribute]);
        b = parseInt(b[attribute]);
        return a - b;
    });
    return array;
 }
});

การใช้งานในมุมมองของคุณ:

<div class="item" ng-repeat="item in items | orderObjectBy:'position'">
    //...
</div>

อ็อบเจ็กต์ต้องการแอ็ตทริบิวต์ตำแหน่งในตัวอย่างนี้ แต่คุณมีความยืดหยุ่นในการใช้แอ็ตทริบิวต์ใด ๆ ในอ็อบเจ็กต์ (ประกอบด้วยจำนวนเต็ม) เพียงแค่ใช้นิยามในมุมมอง

ตัวอย่าง JSON:

{
    "123": {"name": "Test B", "position": "2"},
    "456": {"name": "Test A", "position": "1"}
}

นี่คือซอที่แสดงการใช้งาน: http://jsfiddle.net/4tkj8/1/


1
นี่มันเยี่ยมมาก ฉันเพิ่มตัวเลือกในการจัดเรียง asc / desc: app.filter ('orderObjectBy', function () {return function (input, attribute, direction) {if (! angular.isObject (input)) return input; var array = [] ; สำหรับ (var objectKey ในอินพุต) {array.push (input [objectKey]);} array.sort (function (a, b) {a = parseInt (a [attribute]); b = parseInt (b [attribute]) ; return direction == 'asc'? a - b: b - a;}); return array;}}); ใน HTML: <tr ng-repeat = "val ในรายการ | orderObjectBy: 'prop': 'asc'">
Jazzy

@Armin จะเกิดอะไรขึ้นถ้าเป็น object เช่น array? คือ{1:'Example 1', 2:'Example 2', 3:'Example 3', ...}
ยูจีน

8
คำตอบที่ดี แต่เราทำกุญแจของวัตถุหายไปด้วยวิธีนี้ หากต้องการเก็บไว้เพียงเพิ่มมันสร้างแถวของอาร์เรย์ใหม่ในตัวกรองเช่นfor(var objectKey in input) { input[objectKey]['_key'] = objectKey; array.push(input[objectKey]); }Like ที่เราสามารถใช้ได้<div ng-repeat="value in object | orderObjectBy:'order'" ng-init="key = value['_key']">
Nicolas Janel

7
มันน่าสังเกตว่า Angular.js ไม่... | orderBy: 'name'สนับสนุนการจัดเรียงตามสถานที่ให้บริการในอาร์เรย์ของวัตถุในขณะนี้:
Wildhoney

2
@Wildhoney คำถามนี้เกี่ยวกับการสั่งซื้อวัตถุด้วยคีย์ไม่ใช่อาร์เรย์ที่มีวัตถุ
Armin

31

มันง่ายมากแค่ทำแบบนี้

$scope.props = [{order:"1"},{order:"5"},{order:"2"}]

ng-repeat="prop in props | orderBy:'order'"

33
สิ่งนี้ใช้ไม่ได้กับอาร์เรย์ที่เชื่อมโยงซึ่งเป็นคำถามเกี่ยวกับ
MFB

7

อย่าลืมว่า parseInt () ใช้ได้กับค่า Integer เท่านั้น ในการจัดเรียงค่าสตริงคุณต้องสลับสิ่งนี้:

array.sort(function(a, b){
  a = parseInt(a[attribute]);
  b = parseInt(b[attribute]);
  return a - b;
});

ด้วยสิ่งนี้:

array.sort(function(a, b){
  var alc = a[attribute].toLowerCase(),
      blc = b[attribute].toLowerCase();
  return alc > blc ? 1 : alc < blc ? -1 : 0;
});

6

ดังที่คุณเห็นในรหัสของ angular-JS ( https://github.com/angular/angular.js/blob/master/src/ng/filter/orderBy.js ) ng-repeat ไม่ทำงานกับวัตถุ นี่คือแฮ็คด้วย sortFunction

http://jsfiddle.net/sunnycpp/qaK56/33/

<div ng-app='myApp'>
    <div ng-controller="controller">
    <ul>
        <li ng-repeat="test in testData | orderBy:sortMe()">
            Order = {{test.value.order}} -> Key={{test.key}} Name=:{{test.value.name}}
        </li>
    </ul>
    </div>
</div>

myApp.controller('controller', ['$scope', function ($scope) {

    var testData = {
        a:{name:"CData", order: 2},
        b:{name:"AData", order: 3},
        c:{name:"BData", order: 1}
    };
    $scope.testData = _.map(testData, function(vValue, vKey) {
        return { key:vKey, value:vValue };
    }) ;
    $scope.sortMe = function() {
        return function(object) {
            return object.value.order;
        }
    }
}]);

4

อ้างอิงจากhttp://docs.angularjs.org/api/ng.filter:orderBy orderBy เรียงลำดับอาร์เรย์ ในกรณีของคุณคุณกำลังส่งผ่านวัตถุดังนั้นคุณจะต้องใช้ฟังก์ชันการเรียงลำดับของคุณเอง

หรือส่งอาร์เรย์ -

$scope.testData = {
    C: {name:"CData", order: 1},
    B: {name:"BData", order: 2},
    A: {name:"AData", order: 3},
}

ดูที่http://jsfiddle.net/qaK56/


ฉันรู้ว่ามันใช้ได้กับอาร์เรย์ .. ดังนั้นวิธีแก้คือเขียนฟังก์ชันการเรียงลำดับของฉันเอง?
PrimosK

jsfiddle! = รหัสของคุณที่คุณโพสต์แล้ว นี่คือ jsfiddle ที่ถูกต้องสำหรับตัวอย่างของคุณที่นี่: jsfiddle.net/qaK56/92
mrzmyr

3

คุณควรปรับปรุงโครงสร้าง JSON เพื่อแก้ไขปัญหาของคุณ:

$scope.testData = [
   {name:"CData", order: 1},
   {name:"BData", order: 2},
   {name:"AData", order: 3},
]

จากนั้นคุณสามารถทำได้

<li ng-repeat="test in testData | orderBy:order">...</li>

ฉันคิดว่าปัญหาคือตัวแปร (คีย์ค่า) ไม่สามารถใช้ได้กับตัวกรอง orderBy และคุณไม่ควรเก็บข้อมูลไว้ในคีย์ของคุณอีกต่อไป


2
บอกกับ Firebase;)
MFB

เท่าที่ฉันรู้คุณสร้างข้อมูลใน
firebase

หากคุณจัดเก็บอาร์เรย์ใน Firebase จะใช้ UID เป็นคีย์สำหรับอาร์เรย์ มีหลายสถานการณ์ที่เราไม่สามารถควบคุมโครงสร้างข้อมูลได้ดังนั้นข้อเสนอแนะของคุณอาจดูกว้างเกินไป
MFB

จัดเก็บอาร์เรย์ของอะไร? มีการควบคุมโครงสร้างข้อมูลเสมอ นอกจากนี้ OP ยังไม่ได้ระบุอะไรเกี่ยวกับ Firebase
Joshua Wooward

2

นี่คือสิ่งที่ฉันทำและได้ผล
ฉันเพิ่งใช้วัตถุสตริง

$scope.thread = [ 
  {
    mostRecent:{text:'hello world',timeStamp:12345678 } 
    allMessages:[]
  }
  {MoreThreads...}
  {etc....}
]

<div ng-repeat="message in thread | orderBy : '-mostRecent.timeStamp'" >

ถ้าฉันต้องการจัดเรียงตามข้อความฉันจะทำ

orderBy : 'mostRecent.text'

2

ฉันจะเพิ่มตัวกรองเวอร์ชันอัปเกรดของฉันซึ่งสามารถรองรับไวยากรณ์ถัดไป:

ng-repeat="(id, item) in $ctrl.modelData | orderObjectBy:'itemProperty.someOrder':'asc'

app.filter('orderObjectBy', function(){

         function byString(o, s) {
            s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
            s = s.replace(/^\./, '');           // strip a leading dot
            var a = s.split('.');
            for (var i = 0, n = a.length; i < n; ++i) {
                var k = a[i];
                if (k in o) {
                    o = o[k];
                } else {
                    return;
                }
            }
            return o;
        }

        return function(input, attribute, direction) {
            if (!angular.isObject(input)) return input;

            var array = [];
            for(var objectKey in input) {
                if (input.hasOwnProperty(objectKey)) {
                    array.push(input[objectKey]);
                }
            }

            array.sort(function(a, b){
                a = parseInt(byString(a, attribute));
                b = parseInt(byString(b, attribute));
                return direction == 'asc' ? a - b : b - a;
            });
            return array;
        }
    })

ขอบคุณ Armin และ Jason สำหรับคำตอบในชุดข้อความนี้และ Alnitak ในชุดข้อความนี้


1

คำตอบของ Armin + การตรวจสอบประเภทวัตถุและปุ่มที่ไม่ใช่เชิงมุมอย่างเข้มงวดเช่น $resolve

app.filter('orderObjectBy', function(){
 return function(input, attribute) {
    if (!angular.isObject(input)) return input;

    var array = [];
    for(var objectKey in input) {
      if (typeof(input[objectKey])  === "object" && objectKey.charAt(0) !== "$")
        array.push(input[objectKey]);
    }

    array.sort(function(a, b){
        a = parseInt(a[attribute]);
        b = parseInt(b[attribute]);
        return a - b;
    });

    return array;
 }
})

1

ต่อไปนี้จะช่วยให้การสั่งซื้อของวัตถุโดยคีย์หรือโดยคีย์ภายในวัตถุ

ในเทมเพลตคุณสามารถทำสิ่งต่างๆเช่น:

    <li ng-repeat="(k,i) in objectList | orderObjectsBy: 'someKey'">

หรือแม้กระทั่ง:

    <li ng-repeat="(k,i) in objectList | orderObjectsBy: 'someObj.someKey'">

ตัวกรอง:

app.filter('orderObjectsBy', function(){
 return function(input, attribute) {
    if (!angular.isObject(input)) return input;

    // Filter out angular objects.
    var array = [];
    for(var objectKey in input) {
      if (typeof(input[objectKey])  === "object" && objectKey.charAt(0) !== "$")
        array.push(input[objectKey]);
    }

    var attributeChain = attribute.split(".");

    array.sort(function(a, b){

      for (var i=0; i < attributeChain.length; i++) {
        a = (typeof(a) === "object") && a.hasOwnProperty( attributeChain[i]) ? a[attributeChain[i]] : 0;
        b = (typeof(b) === "object") && b.hasOwnProperty( attributeChain[i]) ? b[attributeChain[i]] : 0;
      }

      return parseInt(a) - parseInt(b);
    });

    return array;
 }
})

เป็นเรื่องปกติหรือไม่ที่คีย์ของ (k, i) ใน objectList จะเปลี่ยนเป็น 0 และ 1
Ken Vernaillen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.