How to move group of items up and down in ng-repeat

I am using ng-repeat to show the items in ui in angular js and i need to move the Items up and down in the ng-repeat table from external button. i am able to move the items up and down but there is one more condition in which i need to move group of items example:

id  reportname comments
1   report1     na
2   report2     test
2   report4     test
3   report3 test
3   report3     na
4   report4     test

I need to move the enitre group of 3,3 above 2,2 or move entire 2,2 below 3,3. Can someone please let me know how can we do that?

Answers


Here is a complete working solution, using Lodash for a bunch of utility methods.

EDIT: Rewrote and refactored to cater for cases where not all items with same id are grouped together. This now only moves adjacent items with the same id, not all items with the same id in the array.

angular.module('stackoverflow', []).controller('MainCtrl', function($scope) {
  $scope.data = [{
    id: 1,
    reportname: 'report1',
    comments: 'na'
  }, {
    id: 2,
    reportname: 'report2',
    comments: 'test'
  }, {
    id: 2,
    reportname: 'report4',
    comments: 'test'
  }, {
    id: 3,
    reportname: 'report3',
    comments: 'test'
  }, {
    id: 3,
    reportname: 'report3',
    comments: 'na'
  }, {
    id: 4,
    reportname: 'report4',
    comments: 'test'
  }];

  $scope.moveGroup = function(item, dir) {
    dir = normalizeDir(dir);
    firstIndexOfGroup
    var firstIndexOfGroup = findFirstIndexWithSameId(item);
    var endIndexOfGroup = findEndIndexOfGroup(firstIndexOfGroup, item);
    var itemsInGroup = $scope.data.slice(firstIndexOfGroup, endIndexOfGroup + 1);
    var idToSwapWith = ($scope.data[firstIndexOfGroup - 1] || {}).id;
    // if moving down, swap with first entry past group end
    if (dir === 'down') {
      idToSwapWith = ($scope.data[endIndexOfGroup + 1] || {}).id;
    }
    if (idToSwapWith > 0) {
      // remove from current position
      $scope.data.splice(firstIndexOfGroup, _.size(itemsInGroup));
      // insert group of items with same id at correct index
      var firstItemWithPrevIdIndex = _.findIndex($scope.data, 'id', idToSwapWith);
      if (dir === 'down') {
        firstItemWithPrevIdIndex = _.findLastIndex($scope.data, 'id', idToSwapWith) + 1;
      }
      var spliceArgs = [firstItemWithPrevIdIndex, 0].concat(itemsInGroup);
      $scope.data.splice.apply($scope.data, spliceArgs);
    }
  };

  $scope.moveItem = function(item, dir) {
    var index = $scope.data.indexOf(item);
    if (normalizeDir(dir) === 'up') {
      $scope.data.splice(index - 1, 2, item, $scope.data[index - 1]);
    } else {
      $scope.data.splice(index, 2, $scope.data[index + 1], item);
    }
  }

  function normalizeDir(dir) {
    switch ((dir || '').toString().toLowerCase()) {
      case 'up':
      case 'u':
        return 'up';
    }
    return 'down';
  }

  function findFirstIndexWithSameId(item) {
    var index = $scope.data.indexOf(item);
    for (var i = index - 1; i >= 0; i--) {
      if ($scope.data[i].id !== item.id) {
        break;
      } else {
        index = i;
      }
    }
    return index;
  }

  function findEndIndexOfGroup(startIndexOfGroup, item) {
    var index = startIndexOfGroup;
    for (var i = startIndexOfGroup + 1, len = _.size($scope.data); i < len; i++) {
      if ($scope.data[i].id === item.id) {
        index = i;
      } else {
        break;
      }
    }
    return index;
  }
});
.move-link-btn {
  font-size: smaller;
  color: lightblue;
  padding: 2px 5px;
}
.move-link-btn:hover {
  text-decoration: underline;
  cursor: pointer;
}
td,
th {
  outline: 1px solid #cfcfcf;
  padding: 2px 5px;
  font-family: sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.8.0/lodash.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="stackoverflow" ng-controller="MainCtrl">
  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>Name</th>
        <th>Comments</th>
        <th>Move Commands</th>
      </tr>
    </thead>
    <tbody>
      <tr ng-repeat="item in data">
        <td>{{item.id}}</td>
        <td>{{item.reportname}}</td>
        <td>{{item.comments}}</td>
        <td>
          <a class="move-link-btn" ng-click="moveItem(item, 'up')">Item Up</a>
          <a class="move-link-btn" ng-click="moveItem(item, 'down')">Item Down</a>
          <a class="move-link-btn" ng-click="moveGroup(item, 'up')">Group Up</a>
          <a class="move-link-btn" ng-click="moveGroup(item, 'down')">Group Down</a>
        </td>
      </tr>
    </tbody>
  </table>
</div>

I create small demo for up and down element in ng-repeat http://plnkr.co/edit/mBoIY5ZCCQA4sRSVHuQB?p=preview Please see this and review it.

In above demo add

<input type="button" name="changeOrder" ng-click="changeReportOrder()" value="Change Order">
    <div ng-repeat="report in reports | orderBy:predicate:reverce">{{report.id}} {{report.reportname}} {{report.comments}}</div>

in body tag and

$scope.reports = [
    {id:1,reportname:'report1',comments:'na'},
    {id:2,reportname:'report2',comments:'test'},
    {id:2,reportname:'report4',comments:'test'},
    {id:3,reportname:'report3',comments:'test'},
    {id:3,reportname:'report3',comments:'na'},
    {id:4,reportname:'report4',comments:'test'}
    ];
    $scope.predicate = '-id';
    $scope.changeReportOrder = function(){
      if($scope.predicate == 'id')
        $scope.predicate = '-id';
      else
        $scope.predicate = 'id';
    }

In controller. and order change ascending/descending of reports base on id when click on Order Change button.


Need Your Help

Print to a Dot-Matrix Printer directly from VB.NET

vb.net printing epson dot-matrix

i am finishing a program i am writing and i have to create a printing to an Epson LQ-300+ Dot-Matrix. The printing has to print some text in some specific parts of the paper (Amount,name etc)

How to fail over node.js timer on amazon load balancer?

node.js amazon-web-services amazon-elb

I have setup 2 instance under aws load balancer. I have deployed node.js web services + mongodb in both instance. load balancer works fine with web services.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.