Last year, I played a lot with jQueryUI and mostly draggable/droppable along with AngularJS and it was a bit of a pain so I decided to write a directive for it which should make it easy for others to implement such functionalities.
Demos and much more
http://codef0rmer.github.com/angular-dragdrop/#/
Fork it on Github
https://github.com/codef0rmer/angular-dragdrop
and written test cases also 🙂
https://github.com/codef0rmer/angular-dragdrop/blob/master/test/index.html
Good Night!
If you found this article useful in anyway, feel free to donate me and receive my dilettante painting as a token of appreciation for your donation.
[…] Checkout Angular Module to implement drag-and-drop more seemlessly […]
I get a “Error: Argument ‘oneCtrl’ is not a function, got undefined” when I define the controller as
App.controller(‘oneCtrl’, function($scope, $timeout) {……
But when I change it to
var ExploreController = [‘$scope’,’$http’, ‘$timeout’, function($scope,$http,$timeout){….
the error goes away, but the drag n drop does not work.. I am sure i am doing a rookie mistake.. any advice?
Sorry, I meant var oneCtrl = [‘$scope’,’$http’, ‘$timeout’, function($scope,$http,$timeout){….
in the previous line..
Can you make a demo on jsfiddle.net?
I got it to work..The mistake on my end was I had 2 seperate js files and I was initializing angular.module in both files but injecting jqyoui in only one.
Thanks for replying.
Great. Let me know If you have any suggestions to improve it.
Great module, exactly what I was looking for! The clone on the shopping cart demo isn’t working, do you know a quick fix for that before I dive into your code? Thanks!
can you explain what error do you get?
For me, it seems to be working. Checkout this demo: http://plnkr.co/0Dj869goYSrQy53ePJpz/preview
What I meant is that it isn’t cloning, using Chrome when I look at your shopping cart and the jQuery UI shopping cart (http://jqueryui.com/droppable/#shopping-cart) the jQuery one clones the element but yours doesn’t.
Oh I see. Actually when you set helpers:’clone’ for jqueryUI draggable that means the actual element will not be moved while dragging which is whats happening in my demo as well. But in jqueryUI demo, the products listing is not dynamic (its static) which is why a product is not removed once dropped in the cart. I think this is what you are referring at.
That you can achieve by adding the same item again in your $scope.list1 after dropping it using onDrop event. Hope this helps!
@brahner: I’ve updated the module to support what you expected. Just mention placeholder:’keep’ on your draggables.
Great, thank you!
Thanks Amit! Its working good!
I have one query. The animation doesn’t seems to work with table rows (by animation I mean, the dragged row should be moveable). The action drag does affect the model though and the swap happens. I am using this snippet:
Thanks
Thanks Prakhar. I think It wont work with tables because HTML table element does not support that. You need to use divs only.
Thanks Amit. I need some Help. I wanted to store the Sequence of Drag & Drop Element in Database. Can U Explain that How Can i Solve the Problem?
Offcourse! jqyoui-draggable takes onDrop callback which triggers when a draggable is dropped inside some droppable area. In onDrop callback, just get the updated model data and store it in DB.
Ok… But main thing is how can I to get this onDrop Value???
Hey swarup, all callbacks give access to event and ui objects so you can just grab the updated list using $scope.list1(draggable list) and $scope.list2(droppable list).
Also using ui object in dropCallback, you can grab the draggable’s model with “angular.element(ui.draggable).scope().item” or the parent scope “angular.element(ui.draggable).scope().$parent” that lists all the models bound to the scope – list1 and list2 in this case.
Hope this helps!
I think I’m Very Confused. Because It’s doesn’t work. Ok Will Show u The Code. & After that U Suggest Me.
hello.js is my js File:-
var App = angular.module(‘drag-and-drop’, [‘ngDragDrop’]);
App.controller(‘oneCtrl’, function($scope, $timeout) {
$scope.details = [{name:’John’, address:’New Town’, phone:’555-1276′},
{name:’Mary’, address:’Old Town’, phone:’800-BIG-MARY’}];
& Hello.html is my html File:-
User Details 1
{{info.name}}
{{info.address}}
{{info.phone}}
I want to Store the Sequence of values… If I Arrange the Sequence . then Sequence will be store. I try But It Doesn’t working. & I’m New in JavaScript. So Please Help me…
HTML File Is
User Details 1
{{info.name}}
{{info.address}}
{{info.phone}}
Hey Swarup, can you create a simple demo on jsfiddle or plunkr instead of pasting the code here?
I Don’t know Why Html File is not Display. Ok. My HTML has a Table where I want to arrange the Table Row Value & Store the Sequence of Table Row…
On Table Tag I Defined
data-drop=”true” ng-model=’details’ jqyoui-droppable=”{multiple:true}”
& On Table Row Tag I Defined
ng-repeat=’info in details’ data-drag=”true” data-jqyoui-options=”{revert: ‘invalid’, helper: ‘clone’}” ng-model=”details” jqyoui-draggable=”{index: {{$index}}, animate: true}”
Now Tell Me What I’ll do???
Is there a way for the Droppable to veto the drop. I had hoped that the overCallback or dropCallback could return true or false to indicate whether the drop is allowed or not. Is there another way?
I assume you want to restrict some items to be dropped – correct me if I’m wrong.
Take a look at: http://api.jqueryui.com/droppable/#option-accept
Exactly – I have a list from which I drag and I drop into one or more containers. Items from the list can be dragged to one or more containers, i.e. the item in the list must remain after being dragged to one container to enable dragging to a second or third container. All that works. The restriction I now need is that an item from the list must only be dropped once into each container.
I am trying to stay in the Angular “world” (I get the feeling that I need to drop into DOM territory if I am using “accept”) hence it would be nice if the callback methods could be used to indicate whether the item could be dropped or not.
‘accept’ option does not take you to DOM territory as there is no implicit DOM manipulation involved.
Have you seen this example where the first list only accepts two items? http://codef0rmer.github.io/angular-dragdrop/#/list
In addition, create a short demo on jsfiddle or plunkr for me to check.
Thanks for that – I had missed this example. Looks like what I need.
Thanks again for your reply – I tried the “accept” option and it works fine.
Just one more thing – the source list contains one type of JSON objects while the destination lists should contain a different type of JSON objects that would contain some information from the source object. I guess I could do some object swapping in the “drop” callback, but is there a better way? Maybe a transformation “hook” just before the source object is added to the destination list, e.g. a “about-to-drop” callback.
Before drop event is not supported by jQueryUI as of now. onDrop callback is an ideal place to do some post drop stuff. May be you could send a PR to jQueryUI project on github to propose ‘beforeDrop’ callback.
Thanks – I will see how I go with the onDrop first. Cheers.
Can u make a option that ng-repeat come out where it dorp like this http://jsfiddle.net/Rusln/MZLvN/ I not good enough to create it by my own hand.
Amit, good job with the drag and drop directive. Do you have a demo any where which shows the onDrop implementation? For me, the code cannot find the bound event handler in the scope.
Thanks Nishanth..! Try this: https://github.com/codef0rmer/angular-dragdrop/blob/master/demo/dnd-frameworks.html
do you have any example where you can drag one item inside a drop zone and then use this as a group that you can drag and drop into a new drop zone?
I believe you can. Just give it a try and let me know if any problem persists.
HI, I have a issue when using complex models. Here is the plunker. http://plnkr.co/edit/2cofW623YkNOPQeYu87b?p=preview. Basically I want to drag just the child elements not the parent. How do I create a drop placeholder for the drop of child elements. ANy help will be great
Can you open an issue for the same on Github? Also, elaborate on what you exactly doing?
Hey codeformer, loving the module! If this works, it will make my transition from jQuery to Angular much smoother. I am just running into one snag.
The objects I am dragging are in scrollable divs, and I need to drag them into other scrollable divs. When I attempt to do this, they can’t be dragged outside of their parent.
In data-jqyoui-options, I have tried setting options for containment, but the setting isn’t being honored. I have also tried to define a helper function in the jQuery options, but the helper function isn’t being linked… the code inside the function never fires.
Have you encountered this before? Do you know of any workarounds?
Never mind, I figured it out… Containment had nothing to do with it.
The answer is in figuring out why the helper function wasn’t firing. The module uses $scope.eval() to evaluate the attribute, which means the function must be visible using $scope.eval().
Just in case anybody else has this issue, here is how I did it:
1) place an empty in the document root.
2) in your VM, be sure to attach the helper function to the VM.
vm.draghelper = function(event){
return $(event.target).parents(‘div.address’).clone()
.insertAfter($(“#dragdrop_element_helper”));
}
3) If you use Controller As, be sure to include that in the directive attribute:
data-jqyoui-options=”{revert: ‘invalid’, containment: ‘window’, opacity: 0.35, helper: addressVm.draghelper}”
Not that’s possible. You have to set overflow:hidden on a droppable so that you could drag outside it without getting scrollbar in a way.
I really liked your idea. Did you ever try to hookup ngDragDrop with requireJs?? I am getting an error while hooking up with requirejs
error is
TypeError: undefined is not a function
at angular.module.service.directive.link.updateDraggable
Did you get the solution ?
I did not try but it will be pretty straight forward.
How to implement the same for touch events.
Include touchpunch.js before jquery-ui.
Please share a demo for touch devices
I have Issue with touch devices.Here is the plunker. As you suggested Included touchpunch.js too
http://plnkr.co/edit/g821F3jRszScxiE0swhK?p=preview
Hi There CodeFormer.
Great module, thank you so much for creating this. I am using the shopping carrt example and I want to remove the items in my cart I I added too many of one thing. How can I do that?
On my controller I have this
$scope.fadeOut = function ($event) {
$event.preventDefault();
$event.stopPropagation();
// make it fade away and remove it from the list
}
Then On the Html I have this
{{item.title}}
Have a demo for me to understand the problem properly?
Hello CodeFormer,
I would like to thanks for good directive.
I am having issue is that when i drag and item and putting item to another cell of table where i shows drop an item over here, it add new row where i want the cell should be populated with dropped item.
http://plnkr.co/edit/3rBuLVQ2MyJaMP6xcsnE?p=preview
Now I can do drag and drop using html table as below, but i want to replace the value where i drop not duplicates the values in target table.
Help is really appreciated
http://plnkr.co/edit/jOtzmtAUO8n3WbyzCrm8?p=preview
I am in same boat as @Ace here. In your demo of shopping cart, you allow user to add items to shopping cart. That’s fine. But what if user want to remove item from the shopping cart using drag & drop. Currently, in your demo, it doesn’t allow to remove an item from shopping cart. Is there any way to do it?
That’s because I’ve
jqyoui-draggable="{placeholder: 'keep'}"
. If you remove the placeholder option, the dragged item will be removed from the source list once dropped.Looks like you didn’t got my point i guess. I want to remove item from “shopping cart” – right section of of your demo. I don’t want remove item from product list.
Ohk. Again it’s because there is no drop region other than the right section. So you need to make the left sections droppable to make it work.
But when i do that in angularjs app, the item which is dragged from shopping cart is getting added to left section or shows a duplicate item angularjs error. I only want to remove the item from shopping cart when user drags it out from shopping
Use `track by` in ngRepeat to avoid duplicate items error. Note that you can only remove items on drop – there is no other way.
Hello codef0rmer
How can i restrict a draggable to be dropped only once on the drop zone.
Basically I need to get the data which i am dragging and then do some evaluation between current data which is available on the drop zone and the data which i am dragging and then allow the dragged item to be dropped on the drop zone
Please help
Do you have a demo which I can fix?