2013-05-08 3 views
29

私はこのようなorderByフィルタでng-repeatを使用してオブジェクトのリストをレンダリングしています:ng-animateでng-repeatを使用してorderByでリストをソートする方法を教えてください。

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

リストのソートの変化を、アニメーション化ngのための私の試みはイライラ証明と共有する価値がないています。私はYearofmooのサンプルアプリケーションhereを見てきました。

残念ながら、このデモは私が達成しようとしているものではありません。私は、orderByの定義が変更された後、新しいオーダーに配置されたときに、指定されたリスト項目のX位置をアニメーション化する必要があります。私はCSSの遷移と絶対配置でこれを達成しようとしましたが、ng-repeatorderByのリスト項目を再現してアニメーションを本当の挑戦にしているようです。

  1. ng-repeat | orderBy(とやng-animate なし)でこれは可能ですか?
  2. アプローチを提案したり、例を挙げたりできますか? @Alexオズボーンは、あなたがここに私の試みで、コメントで欲しいものを行う方法が示されている場合でも、
+5

私はこの問題に遭遇しましたが、ソリューションを構築するために持っていなかった、または私は例を挙げて、適切な答えを提供するだろう - しかし、私が予定していた解決策は、リストのコピーをフィルタリングすること(コントローラ内で)、アイテムの新しいインデックスを見つけて、そのアイテムをそのインデックスに移動させるアニメーションでした。あなたはそうです - フィルター+ ng-repeatはリストを再構築するだけです。あなたが実際に望むのは、アニメーションの処理から位置を決定することです。 –

+0

私はそれが解決策かもしれないことを恐れていました - ありがとう! – Casey

+0

@AlexOsborn答えとして提出する必要があります。それは私を助けた! –

答えて

41

ので、:だから

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>

を、AngularJSはしていませんアイテムを注文しますが、CSS属性topng-style="{top: ...}")が変更されます。 AngularJSはリストを再作成せず、素敵なアニメーションが得られます。 :)

+0

これをまとめてくれてありがとう! – Casey

+6

この解決策は、DOMの順序ではなく、要素の 'top'スタイルの属性のみを変更することに注意してください(これはおそらく動作します - 要素はAngularによって削除され、読み込まれません)。これは視覚的に重要ではありませんが、アクセシビリティの面では悪いです。スクリーンリーダーを持った盲目のユーザーは、常に最初のレンダリングの元の順序を取得します。このトピックのWCAGガイドラインを参照してください。http://www.w3.org/TR/WCAG20-TECHS/C27.html – denisw

+0

むしろコードの大部分を書くと、javascriptのreverse()関数を直接使用できます。 var list = CompanyList []; reverseelist = list。逆(); ng-repeat = "リセルリストのアイテム" –

11

リストをグリッドとして表示できるように、AndreM96の回答が拡張されました。

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

コードはどこですか? – krivar

+8

上記の[デモの表示]リンクをクリックすると、ブラウザの右上にある[js binに編集]ボタンが表示されます。 PS:あなたの質問はちょっと失礼です。あなたが次回よりきれいに尋ねると感謝します。ありがとう。 – robro

+0

ご回答いただきありがとうございました。私は次回より気をつけます。 – krivar

関連する問題