Component to handle multiple lists easily with minimal code + multi-selection
iranor1 opened this issue · 0 comments
iranor1 commented
Hello,
I found your module very useful for an in-house app I am building. I just wanted to share a component I built around it to make it simpler to make multiple lists without too much boilerplate code.
Features:
- Display multiple drag-drop list with one line of code each
- Select multiple elements and drag them to another list
- Shift+click to select elements in-between (doesn't handle unselection yet)
- Choose if elements are added at end of list or in selected spot
- Specify elements to hide without removing them from the list
It works but it needs more polishing. If it may help someone of give you some ideas...
Example:
<drag-list list="parentsToLink" title="Parents" height="210"></drag-list>
<drag-list list="childrenToLink" title="Children" height="210"></drag-list>
In controller
$scope.parentsToLink = {items: $scope.linkedAsset.parents) , dragging: false};
$scope.childrenToLink = {items: $scope.linkedAsset.children), dragging: false};
dragList.js
app.component('dragList', {
transclude: true,
bindings: {
list: '=',
onUpdate: '&',
addAtEnd: '<',
filterIds: '<',
title: '@',
height: '@'
},
controller: function($scope) {
var self = this;
$scope.lastSelection = null;
self.$onInit = function(){
if (angular.isUndefined(this.addAtEnd) || this.addAtEnd=== null){
this.addAtEnd = true;
}
if (angular.isUndefined(this.height) || this.height=== null){
this.height = 200;
}
}
self.$onDestroy = function(){
if(self.list != null){
self.list.items.forEach(function(item){
item.selected = false;
});
}
}
$scope.filterElements = function(){
return function(item) {
return !$scope.isFiltered(item.id);
}
}
$scope.selectedItem = function(item, e, list){
item.selected = !item.selected;
if(e.shiftKey){
var lastSelectedIndex = list.items.indexOf($scope.lastSelection);
var currentIndex = list.items.indexOf(item);
if(currentIndex > lastSelectedIndex){
for(var i=lastSelectedIndex; i<currentIndex; i++){
if(!$scope.isFiltered(list.items[i].id)){
list.items[i].selected = true;
}
}
} else {
for(var i=currentIndex; i<lastSelectedIndex; i++){
if(!$scope.isFiltered(list.items[i].id)){
list.items[i].selected = true;
}
}
}
} else {
$scope.lastSelection = item;
}
}
$scope.isFiltered = function(id){
if(self.filterIds){
return self.filterIds.indexOf(id) > -1;
}
return false;
}
$scope.getSelectedItemsIncluding = function(list, item) {
item.selected = true;
return list.items.filter(function(item) { return item.selected; });
}
$scope.onDragstart = function(list, event) {
list.dragging = true;
}
$scope.onDrop = function(list, items, index) {
angular.forEach(items, function(item) { item.selected = false; });
if(self.addAtEnd){
list.items = list.items.concat(items);
}
else {
list.items = list.items.slice(0, index)
.concat(items)
.concat(list.items.slice(index));
}
return true;
}
$scope.onMoved = function(list) {
list.items = list.items.filter(function(item) { return !item.selected; });
self.onUpdate();
}
},
templateUrl: 'components/dragList.html'
});
css file
/* DragDropList */
.panel-body { padding: 5px; }
.panel-heading { padding: 5px; }
.dragDropList ul[dnd-list] {
min-height: 30px;
padding-left: 0px;
height: 90%;
}
.dragDropList ul[dnd-list] .dndDraggingSource {
display: none;
}
.dragDropList ul[dnd-list] .dndPlaceholder {
background-color: #ddd;
display: block;
min-height: 5px;
}
.dragDropList ul[dnd-list] li {
background-color: #fff;
border: 1px solid #ddd;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
display: block;
padding: 3px 3px;
margin-bottom: -1px;
font-size: 12px;
}
.dragDropList ul[dnd-list] li.selected {
background-color: #dff0d8;
color: #3c763d;
}
The file dragList.html
<div style="width: 100%" class="dragDropList">
<div class="panel panel-info">
<div class="panel-heading" ng-if="$ctrl.title">
<h3 class="panel-title">{{$ctrl.title}}</h3>
</div>
<div class="panel-body" style="height: {{$ctrl.height}}px; overflow-y: auto">
<ul dnd-list dnd-drop="onDrop($ctrl.list, item, index)">
<li ng-repeat="item in $ctrl.list.items | filter: filterElements()"
dnd-draggable="getSelectedItemsIncluding($ctrl.list, item)"
dnd-dragstart="onDragstart($ctrl.list, event)"
dnd-moved="onMoved($ctrl.list)"
dnd-dragend="$ctrl.list.dragging = false"
dnd-selected="selectedItem(item, event, $ctrl.list)"
ng-class="{'selected': item.selected}"
ng-hide="$ctrl.list.dragging && item.selected"
>
{{item.name}}
</li>
</ul>
</div>
</div>
</div>