Created
March 22, 2017 14:12
-
-
Save treetop1500/c0412aac990029425d6dbb193cf1b6cd to your computer and use it in GitHub Desktop.
Sortable Drag and Drop Entities with Symfony and HTML5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var adminNs = | |
{ | |
initDraggableEntityRows: function() { | |
var dragSrcEl = null; // the object being drug | |
var startPosition = null; // the index of the row element (0 through whatever) | |
var endPosition = null; // the index of the row element being dropped on (0 through whatever) | |
var parent; // the parent element of the dragged item | |
var entityId; // the id (key) of the entity | |
function handleDragStart(e) { | |
dragSrcEl = this; | |
entityId = $(this).attr('rel'); | |
dragSrcEl.style.opacity = '0.4'; | |
parent = dragSrcEl.parentNode; | |
startPosition = Array.prototype.indexOf.call(parent.children, dragSrcEl); | |
console.log("start: "+startPosition); | |
e.dataTransfer.effectAllowed = 'move'; | |
e.dataTransfer.setData('text/html', this.innerHTML); | |
console.log(entityId); | |
} | |
function handleDragOver(e) { | |
//console.log('drag over: '+ e.target); | |
if (e.preventDefault) { | |
e.preventDefault(); // Necessary. Allows us to drop. | |
} | |
e.dataTransfer.dropEffect = 'move'; // See the section on the DataTransfer object. | |
return false; | |
} | |
function handleDragEnter(e) { | |
//console.log('drag enter: '+ e.target); | |
this.classList.add('over'); | |
} | |
function handleDragLeave(e) { | |
//console.log('drag leave: '+ e.target); | |
this.classList.remove('over'); // this / e.target is previous target element. | |
} | |
function handleDrop(e) { | |
//console.log('drop: '+ e.target); | |
//console.log(e.currentTarget); | |
//console.log(dragSrcEl); | |
if (e.stopPropagation) { | |
e.stopPropagation(); // stops the browser from redirecting. | |
} | |
// Don't do anything if dropping the same column we're dragging. | |
if (dragSrcEl != this) { | |
endPosition = Array.prototype.indexOf.call(parent.children, this); | |
console.log("end: "+endPosition); | |
// Set the source column's HTML to the HTML of the column we dropped on. | |
dragSrcEl.innerHTML = this.innerHTML; | |
this.innerHTML = e.dataTransfer.getData('text/html'); | |
// do the ajax call to update the database | |
$.ajax({ | |
url: '/admin/productcategory/sort/'+entityId+'/'+endPosition, | |
}) | |
.done(function(res) { | |
$("table.sortable tbody").replaceWith($(res).find("table.sortable tbody")); | |
}) | |
.fail(function(err) { | |
alert("An error occurred while sorting. Please refresh the page and try again.") | |
}) | |
.always(function() { | |
adminNs.initDraggableEntityRows(); | |
}); | |
} | |
return false; | |
} | |
function handleDragEnd(e) { | |
//console.log('drag end: '+ e.target); | |
this.style.opacity = '1'; // this / e.target is the source node. | |
[].forEach.call(rows, function (row) { | |
row.classList.remove('over'); | |
}); | |
} | |
var rows = document.querySelectorAll('table.sortable > tbody tr'); | |
[].forEach.call(rows, function(row) { | |
row.addEventListener('dragstart', handleDragStart, false); | |
row.addEventListener('dragenter', handleDragEnter, false); | |
row.addEventListener('dragover', handleDragOver, false); | |
row.addEventListener('dragleave', handleDragLeave, false); | |
row.addEventListener('drop', handleDrop, false); | |
row.addEventListener('dragend', handleDragEnd, false); | |
}); | |
}, | |
/** | |
* Primary Admin initialization method. | |
* @returns {boolean} | |
*/ | |
init: function() { | |
... | |
this.initDraggableEntityRows(); | |
return true; | |
} | |
}; | |
$(function() { | |
adminNs.init(); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
services: | |
... | |
gedmo.listener.sortable: | |
class: Gedmo\Sortable\SortableListener | |
tags: | |
- { name: doctrine.event_subscriber, connection: default } | |
calls: | |
- [ setAnnotationReader, [ "@annotation_reader" ] ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<table class="sortable"> | |
<thead> | |
<tr> | |
<th> </th> | |
<th>Id</th> | |
<th>Sort</th> | |
<th>Title</th> | |
</tr> | |
</thead> | |
<tbody> | |
{% for category in productCategories %} | |
<tr draggable="true" rel="{{ category.id }}"> | |
<td><i class="fa fa-arrows"></i></td> | |
<td><a href="{{ path('admin_productcategory_show', { 'id': category.id }) }}">{{ category.id }}</a></td> | |
<td>{{ category.position }}</td> | |
<td>{{ category.title }}</td> | |
</tr> | |
{% endfor %} | |
</tbody> | |
</table> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Common\ContentBundle\Entity; | |
... | |
use Gedmo\Mapping\Annotation as Gedmo; | |
class ProductCategory | |
{ | |
... | |
/** | |
* @var integer $position | |
* | |
* @Gedmo\Sortable() | |
* @ORM\Column(name="position", type="integer") | |
*/ | |
private $position; | |
... | |
/** | |
* @return int | |
*/ | |
public function getPosition() | |
{ | |
return $this->position; | |
} | |
/** | |
* @param int $position | |
*/ | |
public function setPosition($position) | |
{ | |
$this->position = $position; | |
} | |
... | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Common\ContentBundle\Controller; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Bundle\FrameworkBundle\Controller\Controller; | |
use Common\ContentBundle\Entity\ProductCategory; | |
/** | |
* ProductCategory controller. | |
*/ | |
class ProductCategoryController extends Controller | |
{ | |
... | |
/** | |
* Resorts an item using it's doctrine sortable property | |
* @param integer $id | |
* @param integer $position | |
* @return \Symfony\Component\HttpFoundation\Response | |
*/ | |
public function sortAction($id, $position) | |
{ | |
$em = $this->getDoctrine()->getManager(); | |
$productCategory = $em->getRepository('CommonContentBundle:ProductCategory')->find($id); | |
$productCategory->setPosition($position); | |
$em->persist($productCategory); | |
$em->flush(); | |
$request = new Request(); | |
return $this->indexAction($request); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
admin_productcategory_sort: | |
path: /admin/productcategory/sort/{id}/{position} | |
defaults: { _controller: "CommonContentBundle:ProductCategory:sort" } | |
methods: GET |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[draggable] { | |
user-select: none; | |
-webkit-user-drag: element; | |
cursor: move; | |
} | |
table.sortable { | |
i.fa.fa-arrows { | |
color: #999; | |
} | |
tr.over { | |
border: 1px dashed $primary-color; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment