How to Create simple drag and Drop in angularjs

184,165

Solution 1

I just posted this to my brand spanking new blog: http://jasonturim.wordpress.com/2013/09/01/angularjs-drag-and-drop/

Code here: https://github.com/logicbomb/lvlDragDrop

Demo here: http://logicbomb.github.io/ng-directives/drag-drop.html

Here are the directives these rely on a UUID service which I've included below:

var module = angular.module("lvl.directives.dragdrop", ['lvl.services']);

module.directive('lvlDraggable', ['$rootScope', 'uuid', function($rootScope, uuid) {
        return {
            restrict: 'A',
            link: function(scope, el, attrs, controller) {
                console.log("linking draggable element");

                angular.element(el).attr("draggable", "true");
                var id = attrs.id;
                if (!attrs.id) {
                    id = uuid.new()
                    angular.element(el).attr("id", id);
                }

                el.bind("dragstart", function(e) {
                    e.dataTransfer.setData('text', id);

                    $rootScope.$emit("LVL-DRAG-START");
                });

                el.bind("dragend", function(e) {
                    $rootScope.$emit("LVL-DRAG-END");
                });
            }
        }
    }]);

module.directive('lvlDropTarget', ['$rootScope', 'uuid', function($rootScope, uuid) {
        return {
            restrict: 'A',
            scope: {
                onDrop: '&'
            },
            link: function(scope, el, attrs, controller) {
                var id = attrs.id;
                if (!attrs.id) {
                    id = uuid.new()
                    angular.element(el).attr("id", id);
                }

                el.bind("dragover", function(e) {
                  if (e.preventDefault) {
                    e.preventDefault(); // Necessary. Allows us to drop.
                  }

                  e.dataTransfer.dropEffect = 'move';  // See the section on the DataTransfer object.
                  return false;
                });

                el.bind("dragenter", function(e) {
                  // this / e.target is the current hover target.
                  angular.element(e.target).addClass('lvl-over');
                });

                el.bind("dragleave", function(e) {
                  angular.element(e.target).removeClass('lvl-over');  // this / e.target is previous target element.
                });

                el.bind("drop", function(e) {
                  if (e.preventDefault) {
                    e.preventDefault(); // Necessary. Allows us to drop.
                  }

                  if (e.stopPropagation) {
                    e.stopPropagation(); // Necessary. Allows us to drop.
                  }
                    var data = e.dataTransfer.getData("text");
                    var dest = document.getElementById(id);
                    var src = document.getElementById(data);

                    scope.onDrop({dragEl: src, dropEl: dest});
                });

                $rootScope.$on("LVL-DRAG-START", function() {
                    var el = document.getElementById(id);
                    angular.element(el).addClass("lvl-target");
                });

                $rootScope.$on("LVL-DRAG-END", function() {
                    var el = document.getElementById(id);
                    angular.element(el).removeClass("lvl-target");
                    angular.element(el).removeClass("lvl-over");
                });
            }
        }
    }]);

UUID service

angular
.module('lvl.services',[])
.factory('uuid', function() {
    var svc = {
        new: function() {
            function _p8(s) {
                var p = (Math.random().toString(16)+"000000000").substr(2,8);
                return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
            }
            return _p8() + _p8(true) + _p8(true) + _p8();
        },

        empty: function() {
          return '00000000-0000-0000-0000-000000000000';
        }
    };

    return svc;
});

Solution 2

Angular doesn't provide snazzy UI elements like drag and drop. That's not really Angular's purpose. However, there are a few well known directives that provide drag and drop. Here are two that I've used.

https://github.com/angular-ui/ui-sortable

https://github.com/codef0rmer/angular-dragdrop

Solution 3

I'm a bit late to the party, but I have my own directive that looks like it'll fit your case (You can adapt it yourself). It's a modification of the ng-repeat directive that's specifically built for list re-ordering via DnD. I built it as I don't like JQuery UI (preference for less libraries than anything else) also I wanted mine to work on touch screens too ;).

Code is here: http://codepen.io/SimeonC/pen/AJIyC

Blog post is here: http://sdevgame.wordpress.com/2013/08/27/angularjs-drag-n-drop-re-order-in-ngrepeat/

Solution 4

Modified from the angular-drag-and-drop-lists examples page

Markup

<div class="row">
    <div ng-repeat="(listName, list) in models.lists" class="col-md-6">
        <ul dnd-list="list">
            <li ng-repeat="item in list" 
                dnd-draggable="item" 
                dnd-moved="list.splice($index, 1)" 
                dnd-effect-allowed="move" 
                dnd-selected="models.selected = item" 
                ng-class="{'selected': models.selected === item}" 
                draggable="true">{{item.label}}</li>
        </ul>
    </div>
</div>

Angular

var app = angular.module('angular-starter', [
    'ui.router',
    'dndLists'
]);

app.controller('MainCtrl', function($scope){

    $scope.models = {
        selected: null,
        lists: {"A": [], "B": []}
    };

    // Generate initial model
    for (var i = 1; i <= 3; ++i) {
        $scope.models.lists.A.push({label: "Item A" + i});
        $scope.models.lists.B.push({label: "Item B" + i});
    }

    // Model to JSON for demo purpose
    $scope.$watch('models', function(model) {
        $scope.modelAsJson = angular.toJson(model, true);
    }, true);
});

Library can be installed via bower or npm: angular-drag-and-drop-lists

Solution 5

adapt-strap has very light weight module for this. here is the fiddle. Here are some attributes that are supported. There are more.

ad-drag="true"
ad-drag-data="car"
ad-drag-begin="onDragStart($data, $dragElement, $event);"
ad-drag-end="onDataEnd($data, $dragElement, $event);"
Share:
184,165
Priya Bose
Author by

Priya Bose

Updated on July 14, 2022

Comments

  • Priya Bose
    Priya Bose almost 2 years

    I want to know how to do drag and drop by using AngularJs.

    This is what I have so far:

    <span><input type="checkbox" ng-model="master"><span>SelectAll</span></span>
    <div ng-repeat="todo in todos">
    
        <div ng-hide="enableEditor">
            <a href="#">Drag</a>
            <input id="checkSlave" type="checkbox" ng-checked="master" ng-model="todo.done">
    
            <span ng-if="checked" ng-show="removed" ng-bind="todo.task_name" class="removed"></span>
            <span ng-bind="todo.task_name"></span>
            <span ng-bind="todo.state"></span>
            <a href="#" ng-click="editTask(todo.task_id,todo.task_name,editMode=!editMode)">Edit</a> 
    
           </div>
           </div>
    
        <div ng-show="enableEditor">
         <input type="text" ng-show="editMode" ng-model="todo.task_name"  ng-change="update(todo.task_id,todo.task_name)">
         <a href="#" ng-click="saveTask(todo.task_id,todo.task_name,editMode=!editMode)">Save</a>
         <a href="#" ng-click="cancelTask(todo.task_id,todo.task_name,editMode=!editMode)">Cancel</a>
        </div>
    </div>
    

    http://plnkr.co/edit/llTH9nRic3O2S7XMIi6y?p=preview..

  • jcollum
    jcollum over 10 years
    I'm getting an error with this code in Angular 1.2.6. "Multiple directives [lvlDropTarget, tooltip] asking for new/isolated scope on: <div ...". Looks like a collision with bootstrap tooltips.
  • Andrew Magee
    Andrew Magee about 10 years
    I think stopPropogation here should be stopPropagation. Can't do the edit myself as it's less than 6 characters :/
  • DusanV
    DusanV about 10 years
    @AndrewMagee It has been updated in github - github.com/logicbomb/lvlDragDrop
  • CodyBugstein
    CodyBugstein over 9 years
    Why do your attribute names start with x- when the directive names don't?
  • DusanV
    DusanV over 9 years
    Prefixing a nonstandard attribute with x- allows the HTML to pass valuation. It's not necessary, and I probably shouldn't have added them.
  • dwp4ge
    dwp4ge almost 9 years
    If including jQuery and your getting an "Cannot call method 'setData' of undefined" error. Use e.originalEvent.dataTransfer instead of e.dataTransfer
  • caub
    caub over 8 years
    which would you advise?
  • Wasimakram Mulla
    Wasimakram Mulla about 8 years
    This is awesome. It has all the features in it
  • jrran90
    jrran90 about 8 years
    thank you for this, it's not clear on the documentation :) this is much more easy :)
  • Daniel Viglione
    Daniel Viglione almost 8 years
    I haven't tried it yet but the grid looks promising
  • MMR
    MMR over 7 years
    How to include it in my project once after installing it through npm
  • Devner
    Devner over 7 years
    @MMR You can do it in the following way: angular.module("demo", ["dndLists"]); Replace "demo" with your app name. Add angular-drag-and-drop-lists.min.js to the script tag in your HTML file. That should do it.
  • tic
    tic over 7 years
    $rootScope.$on Gross
  • Dennis Xavier
    Dennis Xavier over 4 years
    'ondrop' function doesn't trigger for me.