I created a Fiddle to demonstrate the problem (also can be run inside this question, below).
I have a sidebar of playing card images that I want to drag into a main area. The sidebar holds a lot of cards so I want it to be scrollable. However, when I give it a scroll feature, then when I drag a card, it gets hidden when I drag it out of the sidebar.
var app = angular.module('myApp', ['ngDraggable']); app.controller('ctrl', function ($scope) { });
#gallery-container { overflow-y: scroll; } .card { width: 100%; }
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"/> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.min.js"></script> <script src="https://rawgit.com/fatlinesofcode/ngDraggable/master/ngDraggable.js"></script> <div ng-app="myApp"> <div ng-controller="ctrl"> <div class="row"> <div class="col-xs-3"> <div id="gallery-container"> <div class="row"> <div class="col-sm-12"> <img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt=""> </div> </div> <div class="row"> <div class="col-sm-12"> <img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt=""> </div> </div> <div class="row"> <div class="col-sm-12"> <img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt=""> </div> </div> <div class="row"> <div class="col-sm-12"> <img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt=""> </div> </div> <div class="row"> <div class="col-sm-12"> <img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt=""> </div> </div> <div class="row"> <div class="col-sm-12"> <img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt=""> </div> </div> <div class="row"> <div class="col-sm-12"> <img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt=""> </div> </div> </div> </div> <div class="col-xs-9"> <h2> Drop Area </h2> </div> </div> </div> </div>
When I comment out overflow, like
/*overflow-y: scroll;*/
in the CSS, it now works.
How can I both have a scrolling sidebar and drag items out of it?
overflow: hidden With the hidden value, the overflow is clipped, and the rest of the content is hidden: You can use the overflow property when you want to have better control of the layout. The overflow property specifies what happens if content overflows an element's box.
To prevent scrolling with this property, just apply the rule overflow: hidden to the body (for the entire page) or a container element. This hides all content beyond the element's border.
Use overflow-x : scroll and overflow-y : hidden , or overflow: scroll hidden instead. Use overflow-x : hidden and overflow-y : scroll , or overflow: hidden scroll instead.
hidden : Content that overflows is hidden. scroll : Content is hidden, but users can still scroll through and view the hidden content. auto : If content is bigger than its set dimensions, content will be hidden automatically and a scrollbar will appear.
To drag objects between zones with scrolled or hidden overflows, you need a to create clone div between the drag div and the drop div using the ng-drag-clone
<div ng-drag-clone=""> <img ng-src="{{clonedData .link}}" width="100px"> </div>
I've tried to update your code, but quickly to demonstrate the point:
I noticed you did not create any way for the drop zone to render or store the data being passed.
I created a cards array and a cardsDrop array to store the data.
I also implemented onDropComplete
function to push the card object into cardsDrop
$scope.onDropComplete = function (data, evt) { var index = $scope.cards.indexOf(data); if (index == -1) $scope.cardsDrop.push(data); }
and a onDragComplete
function to remove a card from the original deck (for some applications, this is optional... sometimes you want a list to drag from that does not remove options):
$scope.onDragComplete = function (data, evt) { console.log("133", "$scope", "onDragSuccess1", "", evt); var index = $scope.cards.indexOf(data); if (index > -1) { $scope.cards.splice(index, 1); }
and I used ng-repeat
to render each deck in the drag zone
<div class="row" ng-repeat="card in cards"> <img src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt="" vertical-scroll="false" ng-drag="true" ng-drag-data="card" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" width="100px"> </div>
and drop zones:
<div style="min-height: 300px;" class="col-xs-5" ng-drop="true" ng-scroll="false" ng-drag-move="true" ng-drop-success="onDropComplete($data,$event)"> <draggableClone></draggableClone> <h2> Drop Area </h2> <div ng-repeat="card in cardsDrop" ng-drag-success="onDragComplete($data,$event)" class="card"> <img src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" class="card" alt="" width="100px"> </div> </div>
In addition, I have added some styling to the ng-drag and ng-drop.
The ngDraggable
library you're using does not support adding the element to a parent element (like document.body) once you start dragging. You need that, otherwise the element can never leave the sidebar and keep on being visible. That's how CSS works.
What you could do is use another library that supports adding the draggable element to another element, like jQuery UI:
app.directive('draggable', function() { return function($scope, $element, $attrs) { $element.draggable({ appendTo: 'body', stop: function(event, ui) { // Handle new position } }); }; });
There are probably AngularJS wrappers for Jquery UI out there that do this for you in a more declarative style, or other ngDraggable alternatives that support this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With