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

How to View source page using Wireshark?

networking gzip wireshark pcap chunked-encoding

Is there a possibility that a website's source page can be captured and viewed using Wireshark ? I do not need the header packets, what I am looking for is the full source page of any site that I o...

how to convert java Future<V> to guava ListenableFuture<V>

java concurrency guava futuretask

I need to find a way to convert from Future to ListenableFuture.