Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reorder items of an angularfire backed list, drag and drop style

I'm building an angularjs / firebase app unsing the angularfire bindings (v0.5.0).

I have a list of items, displayed in a table with ng-repeat on the <tr>, something like this:

<table>                               
    <tbody>                                                                
        <tr ng-repeat="(index, item) in items">
            <td>
                <input type="checkbox" ng-model="item.done">
            </td>              
            <td>                                                 
                <input type="text" ng-model="item.text" ng-focus="onItemFocus(index)" ng-blur="onItemBlur(index)">
            </td>                                                              
            <td>                                                               
                <button type="button" ng-click="remove(index)">&times;</button>
            </td>                                                              
        </tr>                                                                  
    </tbody>                                                               
</table>                                                                   

and there's an angularfire 3 way data binding on this list of items, something like:

$scope.ref = new Firebase('...');
$scope.remote = $firebase($scope.ref);
$scope.remote.$child("items").$bind($scope, "items"); 

This works all fine, but now I'm trying to add the possibility to reorder the items with drag and drop.

I managed to setup the drag and dropping UI with jquery-ui (essentially calling $("tbody").sortable()), but my problem is to bind it to the angular models. There's a number of questions regarding that (with great jsfiddles) but in my case the angularfire 3 way binding seems to be messing it up.

I think I need to use firebase priorities with angularfire's orderByPriority and maybe deal with it in one of the sortable callbacks but I'm having trouble figuring out exactly how I should do that... and can't find any sort of documentation about it.

Has anyone done something similar, and could you share some pointers on how to set this up?

like image 654
Jules Olléon Avatar asked Dec 31 '13 14:12

Jules Olléon


1 Answers

I saw your post a long time ago while I was looking for the same solution. Here is something I put together:

function onDropComplete(dropIndex, item) {
if (!item.isNew){
  var dragIndex = $scope.fireData.indexOf(item);
  item.priority = dropIndex;
  $scope.fireData.$save(dragIndex);
  if (dragIndex > dropIndex){
    while ($scope.fireData[dropIndex] && dropIndex !== dragIndex ){
      $scope.fireData[dropIndex].priority = dropIndex+1;
      $scope.fireData.$save(dropIndex);
      dropIndex++;
    }
  } else if(dragIndex < dropIndex){
    while ($scope.fireData[dropIndex] && dropIndex !== dragIndex ){
      $scope.fireData[dropIndex].priority = dropIndex-1;
      $scope.fireData.$save(dropIndex);
      dropIndex--;
    }
  }
} else if (item.isNew){
  item = angular.copy(item);
  item.isNew = false;
  item.priority = dropIndex;
  $scope.fireData.$add(item);
  while ($scope.fireData[dropIndex]){
    $scope.fireData[dropIndex].priority = dropIndex+1;
    $scope.fireData.$save(dropIndex);
    dropIndex++;
  }
}

}

Here, I take items already in the list and have the priority properties of items adjust on drop, depending if the item that was dragged was above or below the drop area. Also, if the drag item in new to the list, it will be added at index where dropped and all items below will be bumped up 1 priority. This is dependent on having your list sorted by var sync = $firebase(ref.orderByChild('priority'));, and you to be using ngDraggable. Here is some HTML for an example:

<tr ng-repeat="obj in fireData" ng-drop="true" ng-drop-success="onDropComplete($index, $data,$event)">
    <td draggable="true" ng-drag="true" ng-drag-data="obj">
      <span class="glyphicon glyphicon-move"></span><div class="drag-name">{{obj.name}}</div>
    </td>
    <td>{{obj.name}}</td>
    <td>{{obj.type}}</td>
    <td><input type="checkbox" ng-change="saveChanges(obj)" ng-model="obj.completed"></td>
    <td>
      <div class="" ng-click="deleteItemFromList(obj)">
        <span class="glyphicon glyphicon-remove"></span>
      </div>
    </td>
  </tr>
like image 62
shteeven Avatar answered Oct 05 '22 22:10

shteeven