2013-05-08 13 views
29

Mam renderowania listę obiektów wykorzystujących ng-repeat z orderBy filtra jak ten:Jak mogę animować sortowanie listy przy użyciu polecenia orderBy przy użyciu polecenia ng-repeat z ng-animate?

<li class="list-item" ng-repeat="item in items | orderBy:predicate:reverse">

Moje próby NG-animować zmiany sortowania listy dowiodły frustrujące i nie warto się dzielić . Widziałem przykładową aplikację Yearofmoo here.

Niestety ta demonstracja nie jest tym, co próbuję osiągnąć. Potrzebuję animować pozycję X danego elementu listy, gdy zostanie on umieszczony w nowej kolejności po zmianie definicji orderBy. Próbowałem tego dokonać z przejściami css i pozycjonowaniem absolutnym, ale wydaje się, że ng-repeat odtwarza elementy listy na orderBy czyniąc animację prawdziwym wyzwaniem.

  1. Czy to możliwe ng-repeat | orderBy (z lub bez ng-animate)?
  2. Czy możesz zaproponować podejście lub podać przykład?
+5

mam natknąć tej kwestii, ale nie musiał zbudować rozwiązanie, czy chciałbym zapewnić prawidłową odpowiedź z przykładów - jednak rozwiązaniem, które planowałem było filtrowanie kopii listy (tj. w kontrolerze), znajdowanie nowego indeksu pozycji, a następnie animowanie przenoszenia pozycji do tego indeksu. Masz rację - filtr + powtórzenie ng tylko odbudowuje listę. To, czego naprawdę chcesz, to oddzielne określenie pozycji od przetwarzania animacji. –

+0

Obawiałem się, że to może być rozwiązanie - dzięki! – Casey

+0

@AlexOsborn Powinieneś to zgłosić jako odpowiedź. Pomogło mi! –

Odpowiedz

41

Tak więc, nawet jeśli @Alex Osborn został pokazany sposób, aby robić to, co chcesz w komentarzach, tutaj jest mój próba:

angular.module('StackApp', []).controller('MainCtrl', function($scope) { 
 
    'use strict'; 
 

 
    $scope.reverse = 'false'; 
 

 
    $scope.myList = [{ 
 
    id: 0, 
 
    text: 'HTML5 Boilerplate' 
 
    }, { 
 
    id: 1, 
 
    text: 'AngularJS' 
 
    }, { 
 
    id: 2, 
 
    text: 'Karma' 
 
    }, { 
 
    id: 3, 
 
    text: 'Hello' 
 
    }, { 
 
    id: 4, 
 
    text: 'World' 
 
    }, { 
 
    id: 5, 
 
    text: 'How' 
 
    }, { 
 
    id: 6, 
 
    text: 'Are' 
 
    }, { 
 
    id: 7, 
 
    text: 'You' 
 
    }, { 
 
    id: 8, 
 
    text: '?' 
 
    }, { 
 
    id: 9, 
 
    text: 'I' 
 
    }, { 
 
    id: 10, 
 
    text: 'write' 
 
    }, { 
 
    id: 11, 
 
    text: 'more' 
 
    }, { 
 
    id: 12, 
 
    text: 'to' 
 
    }, { 
 
    id: 13, 
 
    text: 'make' 
 
    }, { 
 
    id: 14, 
 
    text: 'the' 
 
    }, { 
 
    id: 15, 
 
    text: 'list' 
 
    }, { 
 
    id: 16, 
 
    text: 'longer' 
 
    }]; 
 

 
    $scope.$watch('reverse', function() { 
 
    $scope.setOrder(); 
 
    }); 
 

 
    $scope.setOrder = function() { 
 

 
    if ($scope.reverse === 'random') { 
 

 
     var t = []; 
 

 
     for (var i = 0; i < $scope.myList.length; i++) { 
 
     var r = Math.floor(Math.random() * $scope.myList.length); 
 
     while (inArray(t, r)) { 
 
      r = Math.floor(Math.random() * $scope.myList.length); 
 
     } 
 
     t.push(r); 
 
     $scope.myList[i].order = r; 
 
     } 
 

 
    } else { 
 

 
     for (var i = 0; i < $scope.myList.length; i++) { 
 
     if ($scope.reverse === 'false') { 
 
      $scope.myList[i].order = i; 
 
     } else { 
 
      $scope.myList[i].order = ($scope.myList.length - 1 - i); 
 
     } 
 
     } 
 
    } 
 
    }; 
 

 
    function inArray(a, value) { 
 
    for (var i = 0; i < a.length; i++) { 
 
     if (a[i] === value) { 
 
     return true; 
 
     } 
 
    } 
 
    return false; 
 
    } 
 

 
});
#list { 
 
    /* Needed, otherwise items would be at top of the page (see below) */ 
 
    position: absolute; 
 
    /* full width, or it would look strange */ 
 
    width: 100%; 
 
} 
 
#list li { 
 
    position: absolute; 
 
    /* Top: 0; this will be changed for every single list item by AngularJS */ 
 
    top: 0; 
 
    /* Item height; hold this in sync with template file */ 
 
    height: 40px; 
 
    /* Simple transition */ 
 
    -webkit-transition: top 0.5s ease-in-out; 
 
    -moz-transition: top 0.5s ease-in-out; 
 
    transition: top 0.5s ease-in-out; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script> 
 
<div ng-app="StackApp"> 
 
    <div ng-controller="MainCtrl"> 
 
    <h1>Animate Order</h1> 
 
    <form action=""> 
 
     <label for="reverse">reverse = true</label> 
 
     <br> 
 
     <input type="radio" value="true" name="reverse" ng-model="reverse"> 
 
     <br> 
 
     <br> 
 
     <label for="reverse">reverse = false</label> 
 
     <br> 
 
     <input type="radio" value="false" name="reverse" ng-model="reverse"> 
 
     <br> 
 
     <br> 
 
     <label for="reverse">reverse = random (click button below to shuffle again)</label> 
 
     <br> 
 
     <input type="radio" value="random" name="reverse" ng-model="reverse"> 
 
    </form> 
 
    <br> 
 
    <br> 
 
    <input type="button" ng-click="reverse = 'random';setOrder()" value="setOrder()"> 
 
    <br> 
 
    <br> 
 
    <ul id="list" ng-style="{height: ((myList.length * 40) + 'px')}"> 
 
     <li ng-repeat="item in myList" ng-style="{top: ((item.order * 40) + 'px')}">{{$index}} - {{item.order}}. {{item.text}}</li> 
 
    </ul> 
 
    </div> 
 
</div>

Więc angularjs nie zamówić elementy, ale zmienia atrybut CSS top (ng-style="{top: ...}"). AngularJS nie odtwarza listy i dostajemy ładną animację. :)

+0

Dzięki za złożenie tego razem! – Casey

+6

Należy zauważyć, że to rozwiązanie zmienia tylko atrybuty stylu elementów "top", a nie ich kolejność w DOM (prawdopodobnie dlatego działa - elementy nie są usuwane i odczytywane przez Angular). Chociaż nie ma to znaczenia wizualnie, jest to złe pod względem dostępności: niewidomi użytkownicy z czytnikami ekranowymi zawsze otrzymają oryginalną kolejność pierwszego renderowania. Zobacz wytyczne WCAG na ten temat: http://www.w3.org/TR/WCAG20-TECHS/C27.html – denisw

+0

Zamiast pisania Tak wiele kodu można bezpośrednio użyć funkcji reverse() javascript. var list = CompanyList []; reverselist = lista.rewers(); ng-repeat = "pozycja na liście zmian" –

11

Rozszerzyłem odpowiedź AndreM96, aby umożliwić wyświetlanie listy jako siatki.

angular.module('StackApp', []).config(function($routeProvider) { 
 

 
    'use strict'; 
 

 
    $routeProvider 
 
    .when('/', { 
 
     template: '<h1>Animate Order</h1>' + 
 
     '<form action="">' + 
 
     '<input type="radio" value="true" name="order" ng-model="order">' + 
 
     '<label for="order">reverse</label><br><br>' + 
 

 
     '<input type="radio" value="false" name="order" ng-model="order">' + 
 
     '<label for="order">normal</label><br><br>' + 
 

 
     '<input type="radio" value="random" name="order" ng-model="order">' + 
 
     '<label for="order">random (click button below to shuffle again)</label><br>' + 
 

 
     '</form>' + 
 
     '<input type="button" ng-click="order = \'random\';setOrder()" value="randomize">' + 
 
     '<br><br>' + 
 
     '<ul id="list" ng-style="{height: ((myList.length * 90) + \'px\')}">' + 
 
     '<li ng-repeat="item in myList" ng-style="{top: ((item.row * 90) + \'px\'), left: ((item.column * 90) + \'px\')}">{{$index}} - {{item.order}}. {{item.text}}</li>' + 
 
     '</ul>', 
 
     controller: 'MainCtrl' 
 
    }) 
 
    .otherwise({ 
 
     redirectTo: '/' 
 
    }); 
 

 
}); 
 

 
angular.module('StackApp').controller('MainCtrl', function($scope) { 
 
    'use strict'; 
 

 
    $scope.order = 'false'; 
 

 
    $scope.myList = [{ 
 
     id: 0, 
 
     text: 'HTML5 Boilerplate' 
 
    }, 
 
    { 
 
     id: 1, 
 
     text: 'AngularJS' 
 
    }, 
 
    { 
 
     id: 2, 
 
     text: 'Karma' 
 
    }, 
 
    { 
 
     id: 3, 
 
     text: 'Hello' 
 
    }, 
 
    { 
 
     id: 4, 
 
     text: 'World' 
 
    }, 
 
    { 
 
     id: 5, 
 
     text: 'How' 
 
    }, 
 
    { 
 
     id: 6, 
 
     text: 'Are' 
 
    }, 
 
    { 
 
     id: 7, 
 
     text: 'You' 
 
    }, 
 
    { 
 
     id: 8, 
 
     text: '?' 
 
    }, 
 
    { 
 
     id: 9, 
 
     text: 'I' 
 
    }, 
 
    { 
 
     id: 10, 
 
     text: 'write' 
 
    }, 
 
    { 
 
     id: 11, 
 
     text: 'more' 
 
    }, 
 
    { 
 
     id: 12, 
 
     text: 'to' 
 
    }, 
 
    { 
 
     id: 13, 
 
     text: 'make' 
 
    }, 
 
    { 
 
     id: 14, 
 
     text: 'the' 
 
    }, 
 
    { 
 
     id: 15, 
 
     text: 'list' 
 
    }, 
 
    { 
 
     id: 16, 
 
     text: 'longer' 
 
    } 
 
    ]; 
 

 
    $scope.$watch('order', function() { 
 
    $scope.setOrder(); 
 
    }); 
 

 
    $scope.setOrder = function() { 
 

 
    var i; 
 

 
    if ($scope.order === 'random') { 
 
     var t = []; 
 
     for (i = 0; i < $scope.myList.length; i++) { 
 
     var r = Math.floor(Math.random() * $scope.myList.length); 
 
     while (inArray(t, r)) { 
 
      r = Math.floor(Math.random() * $scope.myList.length); 
 
     } 
 
     t.push(r); 
 
     $scope.myList[i].order = r; 
 
     } 
 
    } else if ($scope.order === 'false') { 
 
     for (i = 0; i < $scope.myList.length; i++) { 
 
     $scope.myList[i].order = i; 
 
     } 
 
    } else { 
 
     for (i = 0; i < $scope.myList.length; i++) { 
 
     $scope.myList[i].order = ($scope.myList.length - 1 - i); 
 
     } 
 
    } 
 

 
    calcGridPosition(); 
 
    }; 
 

 
    function inArray(a, value) { 
 
    for (var i = 0; i < a.length; i++) { 
 
     if (a[i] === value) { 
 
     return true; 
 
     } 
 
    } 
 
    return false; 
 
    } 
 

 
    function calcGridPosition() { 
 
    for (var i = 0; i < $scope.myList.length; i++) { 
 
     var item = $scope.myList[i]; 
 

 
     // columns, left-to-right, top-to-bottom 
 
     var columns = 5; 
 
     item.column = item.order % columns; 
 
     item.row = Math.floor(item.order/columns); 
 

 
     // rows, top-to-bottom, left-to-right 
 
     // var rows = 3; 
 
     // item.column = Math.floor(item.order/rows); 
 
     // item.row = item.order%rows; 
 
    } 
 
    } 
 

 
});
#list { 
 
    position: absolute; 
 
    width: 100%; 
 
    list-style-type: none; 
 
    padding-left: 0; 
 
} 
 

 
#list li { 
 
    position: absolute; 
 
    height: 70px; 
 
    width: 70px; 
 
    background: #ddd; 
 
    -webkit-transition: all 2.5s ease-in-out; 
 
    -moz-transition: all 2.5s ease-in-out; 
 
    transition: all 2.5s ease-in-out; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js"></script> 
 
<main ng-app="StackApp"> 
 
    <div class="container" ng-view></div> 
 
</main>

JSBin Demo

enter image description here

+1

więc gdzie jest kod? – krivar

+8

Kliknij powyższy link "zobacz wersję demonstracyjną", a znajdziesz przycisk "edytuj w js bin" w prawym górnym rogu przeglądarki. PS: Twoje pytanie brzmi trochę niegrzecznie. Byłbym wdzięczny, gdyby następnym razem zapytałeś o więcej. Dzięki. – robro

+0

hej dzięki za odpowiedź i opinię na mój komentarz. Będę bardziej uważać następnym razem. – krivar

Powiązane problemy