Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS directives with HTML5 drag and drop -- issue with scope object

I'm fairly new to angular and I'm having a hard time wrapping my head around where the items are being pushed to. I am not sure if I am correctly setting up the functions to be used with drag/drop and if its getting bound to an older scope object and the ng-repeat isn't being updated properly. I'm thinking there is some slight issue with the way I have this setup. Any pointers or help would be much appreciated.

What should happen is when you drag a color from the Draggable container into the Droppable container it should update the text which is linked to the scope object items. I am successfully pushing an item onto the scope object but ng-repeat isn't picking it up. I am not sure if I need a watch or what to do to get it to pay attention to the newly added items.

JS Fiddle Here: http://jsfiddle.net/RV23R/

HTML CODE:

<div ng-app="my-app" ng-controller="MainController">
<div class="container">
    <header><h1>Draggables</h1></header>
    <section>
        <div draggable="true" ng-repeat="drag_type in drag_types">{{drag_type.name}}</div>
    </section>
</div>
<div class="container">
    <header><h1>Drop Schtuff Here</h1></header>
    <section droppable="true">
        <div><span>You dragged in: </span><span ng-repeat="items in items">{{item.name}},</span></div>
    </section>
</div>

ANGULAR CODE:

var module = angular.module('my-app', []);

module.directive('draggable', function () {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      element[0].addEventListener('dragstart', scope.handleDragStart, false);
      element[0].addEventListener('dragend', scope.handleDragEnd, false);
    }
  }
});

module.directive('droppable', function () {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      element[0].addEventListener('drop', scope.handleDrop, false);
      element[0].addEventListener('dragover', scope.handleDragOver, false);
    }
  }
});

function MainController($scope)
{
    $scope.drag_types = [
        {name: "Blue"},
        {name: "Red"},
        {name: "Green"},
    ];
    $scope.items = [];

    $scope.handleDragStart = function(e){
        this.style.opacity = '0.4';
        e.dataTransfer.setData('text/plain', this.innerHTML);
    };

    $scope.handleDragEnd = function(e){
        this.style.opacity = '1.0';
    };

    $scope.handleDrop = function(e){
        e.preventDefault();
        e.stopPropagation();
        var dataText = e.dataTransfer.getData('text/plain');
        $scope.items.push(dataText);
        console.log($scope.items);
    };

    $scope.handleDragOver = function (e) {
        e.preventDefault(); // Necessary. Allows us to drop.
        e.dataTransfer.dropEffect = 'move';  // See the section on the DataTransfer object.
        return false;
  };

}

CSS (if anyone cares)

.container {
  width: 600px;
  border: 1px solid #CCC;
  box-shadow: 0 1px 5px #CCC;
  border-radius: 5px;
  font-family: verdana;
  margin: 25px auto;
}

.container header {
  background: #f1f1f1;
  background-image: -webkit-linear-gradient( top, #f1f1f1, #CCC );
  background-image: -ms-linear-gradient( top, #f1f1f1, #CCC );
  background-image: -moz-linear-gradient( top, #f1f1f1, #CCC );
  background-image: -o-linear-gradient( top, #f1f1f1, #CCC );
  box-shadow: 0 1px 2px #888;
  padding: 10px;
}

.container h1 {
  padding: 0;
  margin: 0;
  font-size: 16px;
  font-weight: normal;
  text-shadow: 0 1px 2px white;
  color: #888;
  text-align: center;
}

.container section {
  padding: 10px 30px; 
  font-size: 12px;
  line-height: 175%;
  color: #333;
}
like image 609
Skylude Avatar asked Oct 24 '13 22:10

Skylude


1 Answers

There are a couple of typos in the fiddle, but the basic problem is that your drag events are outside an angular digest cycle. You should wrap your changes in $scope.$apply (code sample coming). This forked and bugfixed (FIDDLE) shows that when you click the button, angular shows the changes and refreshes the display with new values.

Fix: (FIDDLE)

$scope.$apply(function() {
    $scope.items.push(dataText);
});

A bug you had is in this code:

<span ng-repeat="items in items">{{item.name}},</span>

This should probably be ng-repeat="item in items", also items only contains the dropped text so it is an array of strings and not the original item objects.

like image 159
Jason Goemaat Avatar answered Nov 12 '22 14:11

Jason Goemaat