How can I animate sorting a list with orderBy using ng-repeat with ng-animate?

后端 未结 2 1913
谎友^
谎友^ 2020-12-02 08:25

I\'m rendering a list of objects using ng-repeat with an orderBy filter like this:

  • 相关标签:
    2条回答
    • 2020-12-02 09:02

      So, even if @Alex Osborn has shown a way to do what you want in the comments, here is my attempt:

      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>

      So, AngularJS doesn't order the items, but it changes the CSS attribute top (ng-style="{top: ...}"). AngularJS doesn't recreate the list and we get a nice animation. :)

      0 讨论(0)
    • 2020-12-02 09:07

      I've expanded upon AndreM96's answer to allow displaying the list as a grid.

      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: #ffffd;
        -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

      0 讨论(0)
    提交回复
    热议问题