AngularJS directives with HTML5 drag and drop -- issue with scope object
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.
Skylude
Updated on June 19, 2022Comments
-
Skylude about 2 years
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; }