Angularjs ha sbagliato $ index dopo orderBy


92

Sono nuovo su Angular.js e ho alcuni problemi a ordinare il mio array e lavorare su quei dati ordinati.

Ho un elenco di articoli e desidero quindi ordinarlo per "Store.storeName", che finora funziona. Ma dopo aver ordinato i dati, la mia funzione di cancellazione non funziona più. Penso che sia perché l'indice $ è sbagliato dopo l'ordinamento, quindi i dati sbagliati vengono cancellati.

Come posso risolverlo? Ordinare i dati nell'ambito e non nella vista? Come farlo?

Ecco un codice pertinente:

Nella vista:

<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>

E nel mio controller ho questa funzione di cancellazione, che dovrebbe eliminare i dati specifici:

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

Funziona bene prima di ordinare nella vista. Se manca qualcosa di importante, fammelo sapere ora.

Grazie!

Risposte:


140

Invece o inoltrando sul $index- che - come avrai notato - punterà all'indice in un array ordinato / filtrato, puoi passare l'elemento stesso alla tua removeItemfunzione:

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

e modificare la removeItemfunzione per trovare un indice utilizzando il indexOfmetodo di un array come segue:

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

1
@ pkozlowski.opensource Sei un genio! Puoi passare un oggetto, non un indice .. Wow !! Grazie uomo.
good_evening

L'array indexOf non è disponibile in Internet Explorer 8 e versioni precedenti.
Peter Hedberg

4
Il titolo della domanda sta chiedendo un indice $ sbagliato dopo orderBy, che questa risposta non risolve. Ci sono casi in cui è necessario il valore $ index corretto (come la selezione dello spostamento su un elenco). Come si ottiene il valore $ index corretto dopo l'applicazione del filtro orderBy?
ClearCloud8

puoi anche creare un nuovo array dall'elenco ordinato all'interno del modello facendo qualcosa del genere: "ele in order_array = (array | filter: filter | orderBy: order_by)"
Porlune

Neat! Grazie fratello.
CENT1PEDE

23

Ho iniziato a imparare l'angolazione e ho affrontato problemi simili e, in base alla risposta di @ pkozlowski-opensource, l'ho risolto semplicemente con qualcosa di simile

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

1
Questo è il migliore e così semplice piuttosto che creare un filtro personalizzato ecc. +1
Rafique Mohammed

1
come è questa non la risposta corretta? Questo ha risolto il mio problema
Cyrus Zei il

19

Ho avuto lo stesso problema e altre risposte in questo argomento non sono adatte alla mia situazione.

Ho risolto il mio problema con il filtro personalizzato:

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;
    };
});

che può essere utilizzato in questo modo:

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

e poi in HTML puoi usare al item.indexposto di $index.

Questo metodo è adatto per le raccolte di oggetti.

Tieni presente che questo filtro personalizzato dovrebbe essere il primo nell'elenco di tutti i filtri applicati (orderBy ecc.) E aggiungerà la proprietà aggiuntiva index(il nome è personalizzabile) a ciascun oggetto della raccolta.


Potresti approfondire il motivo per cui le altre risposte non sono adatte alla tua situazione?
pkozlowski.opensource

1
@ pkozlowski.opensource Questo è molto più pulito. Anche a seconda degli eventi che potrebbero essere allegati e della complessità degli elementi in indexOf molto più efficienti. Inoltre $scope.items.splice($scope.items.indexOf(item),1);non funzionerà come previsto per gli elementi duplicati.
martin

1
@martin dovresti eseguire il backup delle tue affermazioni relative alle prestazioni con numeri reali. Un filtro ha un enorme svantaggio di essere eseguito su ogni ciclo $ digest, quindi non penso che aiuti con le prestazioni ...
pkozlowski.opensource

@ pkozlowski.opensource È vero, e viene eseguito due volte per ogni ciclo $ digest. La cosa importante è "a seconda di quali eventi potrebbero essere allegati", le prestazioni contano quando non si ha il controllo della velocità, ad esempio, evento di scorrimento non regolato - casi estremi lo so.
martin

@mile Beh, ho dei duplicati e questo è quello che stavo cercando, solo un po 'triste che Angular non tenga traccia o l'indice originale in una variabile $. Provai(key, item) in items e non funziona neanche. (la chiave non è conservata all'originale)
Rouche

4

Prova questo:

$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);

}

Puoi trovare una spiegazione dettagliata in questa voce nel mio blog.


2

Nel caso qualcuno abbia bisogno di usare $index, puoi dare un nome all'array ordinato / filtrato:

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

Vedi la mia risposta qui .


Penso che questa risposta vada bene, anche se priva di dettagli. Penso che ciò che hmk significhi è che una volta che l'elenco filtrato è stato messo da parte, come sopra, l'indice può essere usato contro di esso (cioè "SortItems [$ index]") per recuperare la voce desiderata.
Jeremythuff

1

Avrei solo lasciato un commento, ma non ho la "reputazione".

La soluzione di mile è esattamente ciò di cui avevo bisogno anch'io. Per rispondere alla domanda di pkozlowski.opensource: quando hai o annidati ngRepeat, un elenco dinamico (ad es. Dove permetti le rimozioni), o entrambi (che è il mio caso), l'utilizzo $indexnon funziona perché sarà l'indice sbagliato per il back-end i dati dopo l'ordinamento e l'utilizzo ngInitper memorizzare nella cache il valore non funzionano perché non vengono rivalutati quando l'elenco cambia.

Si noti che la soluzione di mile consente di personalizzare il nome della proprietà dell'indice allegato passando un parametro <tr ng-repeat="item in items | index:'originalPosition' | orderBy:'Store.storeName'">

La mia versione ottimizzata:

.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 );
    });
})
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.