The jQuery UI is a mighty library, and I still use it in my projects for its Interactions. Because there are many features, I use the Download tool to select only the items I need and select No Theme as my CSS option.
The Problem
I recently needed to create multiple sortable actions on a flat table, and I would like to share how I accomplished this task with you.
Usually, if you have multiple sortable interactions, it is either done on one extensive nested list or several smaller once linked using the connectWith
and containment
options.
However, I had a flat table with different levels for my last project, which needed to be sorted separately and not mixed.
Below is an example of the table HTML.
<table id="categories">
<tbody>
<tr class="level-0"></tr>
<tr class="level-1"></tr>
<tr class="level-1"></tr>
<tr class="level-0"></tr>
<tr class="level-0"></tr>
<tr class="level-0"></tr>
<tr class="level-1"></tr>
<tr class="level-0"></tr>
<tr class="level-0"></tr>
<tr class="level-1"></tr>
<tr class="level-2"></tr>
<tr class="level-2"></tr>
<tr class="level-2"></tr>
</tbody>
</table>
The 0 is the top level and then 1 and 2 sub-sub levels, respectively.
This is usually done when you return your data in a flat array with an parent
element ID linked to the child ID. For, example:
array( array( "ID" => 1, "parent_ID" => 0, ), array( "ID" => 2, "parent_ID" => 1, ), ... );
If you have done some WordPress programming, you will notice this is something you need to deal with when it comes to taxonomy, either for the default posts and pages or when dealing with custom post types and taxonomies.
The Solution
The JS snippet below is how I was able to complete the task.
var $parent = $( 'table#categories' );
$parent.sortable( {
placeholder: 'ui-state-highlight',
items: '> tr.level-' + depth,
start: function( event, ui ) {
var $elem = $( ui.item );
$( '.ui-state-highlight' ).height( $elem.outerHeight() );
$( '.ui-state-highlight' ).width( $elem.outerWidth() );
}
stop: function( event, ui ) {
var $elem = $( ui.item );
var className = $elem.attr( 'class' ).split( ' ' )[0];
if ( $elem.prev().hasClass( className )
|| $elem.next().hasClass( className ) ) {
var orderId = 0
$.each( $( 'tr.' + className ), function( idx, item ) {
if ( $( item ).hasClass( className ) ) {
orderId++;
$( item ).find( 'input[name="order_id"]' ).val( orderId );
}
} );
return;
}
$( this ).sortable( 'cancel' );
}
} ).disableSelection();
The code above can be improved slightly, but it does the job.
- You can add dynamic depth value from PHP to JS with
wp_localize_script
- I assume that the
level-0
class is always the 1st one on the list with classes but you can do some regular expressions if you aren’t sure this the case in your HTML. - As you can see I store the order ID into a hidden input field so it’s ready to be saved in the database.
‘Til the next time.