Angular Js Drag and Drop - Passing $index to Directive

2.1k Views Asked by At

I have been successful in implementing the Drag and Drop feature in Angular JS.

The basic idea is like Match the City with the Countries. I am able to drag the city and drop in into the Country box. But, the dropped item gets reflected in all the country box. But Since I have used ng-repeat I am finding it hard to fetch the $index value in the directive.

My implementation is here:

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);
        }
    }
});

module.controller("MainController", function ($scope) {
    $scope.questions = [{
        city: "Delhi",
        country: "India"
    }, {
        city: "Tokyo",
        country: "Japan"
    }, {
        city: "Doha",
        country: "Qatar"
    }, ];

    $scope.answers = [];

    $scope.handleDragStart = function (e) {
        this.style.opacity = '0.9';
        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.$apply(function () {
            $scope.answers[id].country = $scope.questions[$index].country
            $scope.answers[id].city = dataText;
        });
        console.log($scope.answers[$index]);
    };

    $scope.handleDragOver = function (e) {
        e.preventDefault();
        e.dataTransfer.dropEffect = 'move';
        return false;
    };
});
.container {
    width: 100%;
    border: 1px solid #CCC;
    box-shadow: 0 1px 5px #CCC;
    border-radius: 5px;
    font-family: verdana;
    margin: 25px auto;
}
.left {
    float: left;
}
.right {
    float : right;
}
.container header {

    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: 300%;
    color: #333;
}
.default {
    clear : both;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="my-app">
    <div ng-controller="MainController">
         <h3>Match the following</h3>

        <div class="container">
            <header>
                 <h1>Drag and drop a city into the corresponding Country box</h1>

            </header>
            <section>
                <div draggable="true" ng-repeat="qs in questions">{{qs.city}}</div>
            </section>
        </div>
        <div class="container" ng-repeat="qs in questions">
            <header>
                 <h1>{{qs.country}}</h1>

            </header>
            <section droppable="true"> <span>{{droppedCity}}</span> 
            </section>
        </div>
        <div class="default"> <pre>{{items|json}}</pre>
        </div>
    </div>
</body>

Any help will be useful. Thanks.

1

There are 1 best solutions below

1
On BEST ANSWER

There are quite a few problems with your code. I'd suggest studying the official documentation and some SO questions related to custom directives and isolate scopes. Here is some updated code with many changes and an updated fiddle:

<body ng-app="my-app">
<div ng-controller="MainController">
     <h3>Match the following</h3>

    <div class="container">
        <header>
             <h1>Drag and drop a city into the corresponding Country box</h1>

        </header>
        <section>
            <div draggable="true" ng-repeat="qs in questions" index="{{$index}}">{{qs.city}}</div>
        </section>
    </div>
    <div class="container" ng-repeat="qs in questions">
        <header>
             <h1>{{qs.country}}</h1>

        </header>
        <section droppable="true" index="{{$index}}"> <span>{{droppedCity}}</span> 
        </section>
    </div>
    <div class="default"> <pre>{{items|json}}</pre>
    </div>
</div>

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

module.directive('draggable', function () {
    return {
        restrict: 'A',
        scope: {
            index: '@'
        },

        link: function (scope, element, attrs) {
            element[0].addEventListener('dragstart', scope.handleDragStart, false);
            element[0].addEventListener('dragend', scope.handleDragEnd, false);
        },
        controller: function($scope) {
            $scope.handleDragStart = function (e) {
                console.log('starting drag', $scope.index);
                this.style.opacity = '0.9';
                e.dataTransfer.setData('text/plain', this.innerHTML);
            };

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

module.directive('droppable', function () {
    return {
        restrict: 'A',
         scope: {
            index: '@'
        },
        link: function (scope, element, attrs) {
            element[0].addEventListener('drop', scope.handleDrop, false);
            element[0].addEventListener('dragover', scope.handleDragOver, false);
        },
        controller: function($scope) {
            $scope.handleDrop = function (e) {
                e.preventDefault();
                e.stopPropagation();
                var dataText = e.dataTransfer.getData('text/plain');
                $scope.$parent.answers.push({country: $scope.$parent.questions[$scope.index].country});
                $scope.$parent.answers.push({city: $scope.$parent.questions[$scope.index].city});                    
            };

            $scope.handleDragOver = function (e) {
                e.preventDefault();
                e.dataTransfer.dropEffect = 'move';
                console.log('dragging over', $scope.$parent.questions[$scope.index].country);
                return;
            };
        }
    };
});

module.controller("MainController", function ($scope) {
    $scope.questions = [{
        city: "Delhi",
        country: "India"
    }, {
        city: "Tokyo",
        country: "Japan"
    }, {
        city: "Doha",
        country: "Qatar"
    }, ];

    $scope.answers = [];
});