AngularJS Drag & Drop with HTML5
Bài đăng này đã không được cập nhật trong 6 năm
Introduction
Chắc hẳn chúng ta cũng không ai xa lạ gì khi nghe đến Angular
nữa, nó là 1 framework rất nổi tiếng củaJavaScripts
với nhiều ưu điểm như: được phát triển bởi Google và là mã nguồn mở viết theo mô hình MVC, cơ chế data-binding 2 chiều, cho phép xây dựng ngay trong trình duyệt giúp code sạch và gọn... và rất nhiều ưu điểm khác. Nếu quan tâm các bạn có thể tìm hiểu thêm, hiện nay có rất nhiều bài viết từ nhiều nguồn khác nhau viết rất chi tiết về framework khá phổ biến này.
Nay mình sẽ giới thiệu về 1 directive
khá hay của AngularJS
, đó là dnd-draggable
. Nói nôm na thì dnd-draggable
là 1 Angular directive
cho phép chúng ta modify 1 list nào đó kết hợp với tính năng drag and drop
API của HTML5
.
Download & Installation
Việc đầu tiên chúng ta cần làm sau khi đã cài AngularJS vào hệ thống, đó là add thêm thư viện angular-drag-and-drop-lists.js
tại đây, sau đó tiến hành include nó vào trong app của bạn:
//= require lib/angular-drag-and-drop-lists
sau đó chúng ta sẽ add thêm module dndLists
vào trong angular app, giả sử ta sẽ có myApp
như sau:
(function() {
angular.module('myApp', ['ui.bootstrap', 'ui.bootstrap.datetimepicker', 'datetimePickerLib', 'dndLists'])
.config(['$httpProvider', '$locationProvider', defaultConfig]);
})();
Vậy là xong phần download và cài đặt. Tiếp theo chúng ta sẽ xem cách dùng nó như thế nào.
How to use
Ta sẽ xây dựng Angular controller có tên demoDragAndDropList
với 2 lists cơ bản như sau:
'user strict;'
angular.module('managerApp').controller('demoDragAndDropListController', demoDragAndDropListController);
function demoDragAndDropListController() {
var vm = this;
var originalList = [{name: "A1"}, {name: "A2"}, {name: "A3"}, {name: "A4"}];
var dragList = [{name: "B1"}, {name: "B2"}, {name: "B3"}, {name: "B4"}];
vm.fields = {
selected: null,
lists: {originalList, dragList}
};
}
Chúng ta cũng có thể dùng $scope
, tuy nhiên việc lạm dụng biến global đôi khi khiến chúng ta gặp khó khăn trong quá trình maintain, chi tiết các bạn có thể tham khảo thêm về $scope
trong AngularJS. Vì thế ở đây mình sẽ dùng vm
.
Sau đó là phía bên View:
<div class="simpleDemo" ng-controller="demoDragAndDropListController as vm">
<div class="col-md-12">
<ul dnd-list="vm.fields.lists.originalList" class="col-md-4">
<li ng-repeat="item in vm.fields.lists.originalList" dnd-draggable="item" dnd-moved="vm.fields.lists.originalList.splice($index, 1)"
dnd-effect-allowed="move" dnd-selected="vm.fields.selected = item" ng-class="{'selected': vm.fields.selected === item}">
{{item.name}}
</li>
</ul>
<ul dnd-list="vm.fields.lists.dragList" class="col-md-4">
<li ng-repeat="item in vm.fields.lists.dragList" dnd-draggable="item" dnd-moved="vm.fields.lists.dragList.splice($index, 1)"
dnd-effect-allowed="move" dnd-selected="vm.fields.selected = item" ng-class="{'selected': vm.fields.selected === item}">
{{item.name}}
</li>
</ul>
</div>
</div>
Sau đó là 1 chút css cho đẹp nếu muốn
/**
* The dnd-list should always have a min-height,
* otherwise you can't drop to it once it's empty
*/
.simpleDemo ul[dnd-list] {
min-height: 42px;
padding-left: 0px;
}
/**
* The dndDraggingSource class will be applied to
* the source element of a drag operation. It makes
* sense to hide it to give the user the feeling
* that he's actually moving it.
*/
.simpleDemo ul[dnd-list] .dndDraggingSource {
display: none;
}
/**
* An element with .dndPlaceholder class will be
* added to the dnd-list while the user is dragging
* over it.
*/
.simpleDemo ul[dnd-list] .dndPlaceholder {
background-color: #ddd;
display: block;
min-height: 42px;
}
.simpleDemo ul[dnd-list] li {
background-color: #fff;
border: 1px solid #ddd;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
display: block;
padding: 10px 15px;
margin-bottom: -1px;
}
/**
* Show selected elements in green
*/
.simpleDemo ul[dnd-list] li.selected {
background-color: #dff0d8;
color: #3c763d;
}
Các bạn có thể xem và demo trực tiếp tại đây.
Ok, vậy là chúng ta đã cơ bản sử dụng được directive dnd-draggable
.
Phần code ở view đại khái là thế này:
-
dnd-draggable
directive sẽ chịu trách nhiệm di chuyển 1 element A nào đó của thẻ HTML, và di chuyển cả object được gán cùng với element A đó. Sau khi element A này được di chuyển,dnd-moved
sẽ đóng vai trò xóa bỏ nó khỏi list ban đầu( ở đây chúng ta dùng methodsplice
để loại bỏ phần tử được select khỏi mảng cũ). -
dnd-selected
là callback sẽ được invoke mỗi khi có element được click nhưng không được drag.Có 1 chút lưu ý nhỏ là 2 lists mình build đều là mảng chứa các hash, chắc hẳn sẽ có câu hỏi là tại sao không là 1 mảng bảo gồm các item luôn cho tiện vd như
var list1 = [A1, A2, A3,..]
. Lúc đầu mình xem demo cũng đặt ra câu hỏi như vậy và đã test thử, tuy nhiên sau đó mình gặp trường hợp lỗi về duplicate keysError: ngRepeat:dupes
khi Angular dùng các keys này để tạo ra DOM cùng với các items ở trongngRepeat
expression. Giải pháp ở trong trường hợp này nếu không muốn phân biệt qua keys của hash, chúng ta cũng có thể dùngtrack by
, có thể track bằng$index
hay 1 properties nào đó của item hiện tại để có được các unique keys. Nhưng trong trường hợp này chỉ mô phỏng lại 1 list khá đơn giản thôi nên mình nghĩ cũng không cần phải cầu kì như vậy, nên dùng hash luôn.
Summary
Bài viết của mình nhằm chia sẻ 1 chút kiến thức hạn hẹp của bản thân về dnd-draggable
- 1 directive khá hay của AngularJS. Cảm ơn bạn đã dành thời gian đọc bài viết.
Nguồn: https://github.com/marceljuenemann/angular-drag-and-drop-lists
All rights reserved