Angularjs ดัชนี $ ผิดหลังจาก orderBy


92

ฉันเพิ่งเริ่มใช้ Angular.js และมีปัญหาในการจัดเรียงอาร์เรย์ของฉันและทำงานกับข้อมูลที่เรียงลำดับนั้น

ฉันมีรายการที่มีรายการและต้องการให้จัดเรียงตาม "Store.storeName" ซึ่งใช้งานได้แล้ว แต่หลังจากจัดเรียงข้อมูลฟังก์ชันลบของฉันไม่ทำงานอีกต่อไป ฉันคิดว่าเป็นเพราะดัชนี $ ผิดหลังจากการเรียงลำดับข้อมูลที่ไม่ถูกต้องจึงถูกลบ

ฉันจะแก้ปัญหานั้นได้อย่างไร? จัดลำดับข้อมูลในขอบเขตและไม่อยู่ในมุมมอง? ต้องทำอย่างไร?

นี่คือรหัสที่เกี่ยวข้อง:

ในมุมมอง:

<tr ng-repeat="item in items | orderBy:'Store.storeName'">
                <td><input class="toggle" type="checkbox" ng-model="item.Completed"></td>
                <td>{{item.Name}}</td>
                <td>{{item.Quantity}} Stk.</td>
                <td>{{item.Price || 0 | number:2}} €</td>                
                <td>{{item.Quantity*item.Price|| 0 | number:2}} €</td>
                <td>{{item.Store.storeName}}</td> 
                <td><a><img src="img/delete.png" ng-click="removeItem($index)">{{$index}}</a></td>
            </tr>

และในคอนโทรลเลอร์ของฉันฉันมีฟังก์ชั่นการลบนี้ซึ่งควรลบข้อมูลเฉพาะ:

$scope.removeItem = function(index){
        $scope.items.splice(index,1);
    }

ใช้งานได้ดีก่อนสั่งซื้อใน View หากสิ่งสำคัญขาดหายไปโปรดแจ้งให้เราทราบทันที

ขอบคุณ!

คำตอบ:


140

แทนหรือการถ่ายทอดบน$index- ซึ่ง - ตามที่คุณสังเกตเห็น - จะชี้ไปที่ดัชนีในอาร์เรย์ที่เรียงลำดับ / กรองแล้วคุณสามารถส่งผ่านรายการไปยังremoveItemฟังก์ชันของคุณได้:

<a><img src="img/delete.png" ng-click="removeItem(item)">{{$index}}</a>

และแก้ไขremoveItemฟังก์ชันเพื่อค้นหาดัชนีโดยใช้indexOfวิธีการของอาร์เรย์ดังนี้:

$scope.removeItem = function(item){
   $scope.items.splice($scope.items.indexOf(item),1);
}

1
@ pkozlowski.opensource คุณคืออัจฉริยะ! ผ่านไอเทมไม่อินเด็กซ์ .. ว้าว !! ขอบคุณคน
good_evening

อาร์เรย์ indexOf ไม่พร้อมใช้งานใน Internet Explorer 8 และต่ำกว่า
Peter Hedberg

4
หัวข้อคำถามกำลังถามเกี่ยวกับดัชนี $ ผิดหลังจาก orderBy ซึ่งคำตอบนี้ไม่ได้อยู่ มีบางกรณีที่คุณต้องการค่าดัชนี $ ที่ถูกต้อง (เช่น shift select ในรายการ) เราจะได้ค่าดัชนี $ ที่ถูกต้องหลังจากใช้ตัวกรอง orderBy ได้อย่างไร?
ClearCloud8

คุณยังสามารถสร้างอาร์เรย์ใหม่จากรายการสั่งซื้อภายในเทมเพลตโดยทำสิ่งนี้: "ele in order_array = (array | filter: filter | orderBy: order_by)"
Porlune

เรียบร้อย! ขอบคุณครับ
CENT1PEDE

23

ฉันเริ่มเรียนรู้เชิงมุมและเผชิญกับปัญหาที่คล้ายกันและจากคำตอบของ @ pkozlowski-opensource ฉันแก้ไขมันด้วยบางสิ่งเช่น

<a>
  <img src="img/delete.png" ng-click="removeItem(items.indexOf(item))">
  {{items.indexOf(item)}}
</a> 

1
วิธีนี้ดีที่สุดและเรียบง่ายแทนที่จะสร้างตัวกรองแบบกำหนดเองเป็นต้น +1
Rafique Mohammed

1
นี่ไม่ใช่คำตอบที่ถูกต้องอย่างไร สิ่งนี้ช่วยแก้ปัญหาของฉันได้
Cyrus Zei

19

ฉันมีปัญหาเดียวกันและคำตอบอื่น ๆ ในหัวข้อนี้ไม่เหมาะกับสถานการณ์ของฉัน

ฉันได้แก้ไขปัญหาของฉันด้วยตัวกรองที่กำหนดเอง:

angular.module('utils', []).filter('index', function () {
    return function (array, index) {
        if (!index)
            index = 'index';
        for (var i = 0; i < array.length; ++i) {
            array[i][index] = i;
        }
        return array;
    };
});

ซึ่งสามารถใช้วิธีนี้:

<tr ng-repeat="item in items | index | orderBy:'Store.storeName'">

และจากนั้นใน HTML คุณสามารถใช้แทนitem.index$index

วิธีนี้เหมาะสำหรับคอลเลกชันของวัตถุ

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


คุณช่วยอธิบายรายละเอียดได้ไหมว่าทำไมคำตอบอื่น ๆ จึงไม่เหมาะกับสถานการณ์ของคุณ
pkozlowski.opensource

1
@ pkozlowski.opensource นี่สะอาดกว่ามาก นอกจากนี้ยังขึ้นอยู่กับเหตุการณ์ที่สามารถแนบได้และความซับซ้อนของรายการในดัชนีมีประสิทธิภาพมากกว่ามาก นอกจากนี้$scope.items.splice($scope.items.indexOf(item),1);จะไม่ทำงานตามที่คาดไว้สำหรับรายการที่ซ้ำกัน
martin

1
@martin คุณควรสำรองข้อมูลการเรียกร้องของคุณเกี่ยวกับประสิทธิภาพด้วยตัวเลขจริง ตัวกรองมีข้อเสียอย่างมากในการดำเนินการในแต่ละรอบการย่อย $ ดังนั้นฉันจึงไม่คิดว่ามันจะช่วยเรื่องประสิทธิภาพ ...
pkozlowski.opensource

@ pkozlowski.opensource นั่นเป็นความจริงและจะทำงานสองครั้งสำหรับแต่ละรอบการสรุป $ สิ่งสำคัญคือ "ขึ้นอยู่กับเหตุการณ์ใดที่สามารถแนบได้" ประสิทธิภาพจะมีความสำคัญเมื่อคุณไม่สามารถควบคุมอัตราได้เช่นเหตุการณ์การเลื่อนที่ไม่มีการควบคุมซึ่งเป็นกรณีที่รุนแรงที่ฉันรู้
martin

@mile ฉันมีรายการที่ซ้ำกันและนี่คือสิ่งที่ฉันกำลังมองหาเพียงแค่เศร้าเล็กน้อยที่ Angular ไม่ติดตามหรือดัชนีดั้งเดิมในตัวแปร $ ฉันลอง(key, item) in itemsแล้วก็ไม่ได้ผลเช่นกัน (ไม่ได้เก็บคีย์ไว้เป็นต้นฉบับ)
Rouche

4

ลองสิ่งนี้:

$scope.remove = function(subtask) {

    var idx = $scope.subtasks.indexOf(subtask),
        st = $scope.currentTask.subtasks[idx];

    // remove from DB
    SubTask.remove({'subtaskId': subtask.id});

    // remove from local array
    $scope.subtasks.splice(idx,1);

}

คุณสามารถค้นหาคำอธิบายโดยละเอียดได้ในรายการนี้ในบล็อกของฉัน


2

ในกรณีที่มีคนต้องการใช้$indexคุณสามารถตั้งชื่อให้กับอาร์เรย์ที่เรียงลำดับ / กรอง:

<tr ng-repeat="item in sortedItems = (items | orderBy:'Store.storeName') track by $index">

ดูคำตอบของฉันที่นี่


ฉันคิดว่าคำตอบนี้ใช้ได้หากขาดรายละเอียด ฉันคิดว่า hmk หมายถึงอะไรก็คือเมื่อรายการที่กรองถูกตั้งค่าไว้ข้างต้นแล้วดัชนีสามารถใช้กับมันได้ (เช่น "sortedItems [$ index]") เพื่อดึงรายการที่ต้องการ
Jeremythuff

1

ฉันจะแสดงความคิดเห็น แต่ฉันไม่มี "ชื่อเสียง"

วิธีแก้ปัญหาของไมล์ก็เป็นสิ่งที่ฉันต้องการเช่นกัน หากต้องการตอบคำถามของ pkozlowski.opensource: เมื่อคุณมีรายการที่ซ้อนกันngRepeatรายการไดนามิก (เช่นที่คุณอนุญาตให้ลบ) หรือทั้งสองอย่าง (ซึ่งเป็นกรณีของฉัน) การใช้$indexไม่ได้ผลเพราะจะเป็นดัชนีที่ไม่ถูกต้องสำหรับส่วนหลัง ข้อมูลหลังจากการเรียงลำดับและใช้ngInitเพื่อแคชค่าจะไม่ทำงานเนื่องจากไม่ได้รับการประเมินซ้ำเมื่อรายการเปลี่ยนแปลง

โปรดทราบว่าโซลูชันของไมล์ช่วยให้สามารถกำหนดชื่อคุณสมบัติดัชนีที่แนบมาได้โดยการส่งผ่านพารามิเตอร์ <tr ng-repeat="item in items | index:'originalPosition' | orderBy:'Store.storeName'">

เวอร์ชันที่ปรับแต่งของฉัน:

.filter( 'repeatIndex', function repeatIndex()
{
// This filter must be called AFTER 'filter'ing 
//  and BEFORE 'orderBy' to be useful.
    return( function( array, index_name )
    {
        index_name = index_name || 'index';
        array.forEach( function( each, i )
        {each[ index_name ] = i;});
        return( array );
    });
})
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.