Jason Jason - 2 months ago 5
Javascript Question

using jquery sortable with css transform/transition

I have a page that uses transform to slide the content when navigating. Some of the content has jQuery sortable table rows. At first, the sorting works as expected. But after clicking a nav item (thus applying a transform and sliding to the desired content), sorting does not act as expected. Instead, when you click on the row to be dragged, it drops below the cursor making it hard to sort. See the CodePen below as an example. Try dragging a row before clicking on the nav, then see the difference after clicking the nav.

Is there a way around this (I have no idea where to start)? Or do I need to find a different way sliding my content?

https://codepen.io/thespareroomstudio/pres/XjrEyg

<nav>
<ul>
<li id='goto_slide-1' class='slideNavItem'>Home</li>
<li id='goto_slide-2' class='slideNavItem'>Not Home</li>
<li id='goto_slide-3' class='slideNavItem'>Far from home</li>
</ul>
</nav>
<main>
<div id='slide-1' class='slide active'>
<table>
<caption>This is a table at home</captin>
<thead>
<tr>
<td>Col 1</td>
<td>Col 2</td>
<td>Col 3</td>
<td>Col 4</td>
<td>Col 5</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
</tbody>
</table>
</div>
<div id='slide-2' class='slide inactive'>
<table>
<caption>This is a table not at home</captin>
<thead>
<tr>
<td>Col 1</td>
<td>Col 2</td>
<td>Col 3</td>
<td>Col 4</td>
<td>Col 5</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
</tbody>
</table>
</div>
<div id='slide-3' class='slide inactive'>
<table>
<caption>This is a table far from home</captin>
<thead>
<tr>
<td>Col 1</td>
<td>Col 2</td>
<td>Col 3</td>
<td>Col 4</td>
<td>Col 5</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
</tbody>
</table>
</div>




body {
overflow: hidden;
}

nav ul li {
display: inline-block;
margin-left: 1em;
cursor: pointer;
}

table {
border-collapse: collapse;
border: 1px solid #000;
margin-bottom: 1em;
}

main {
display: flex;
width: 303%;
}

.slide {
width: 100%;

margin: 1em;
}

table tr:nth-child(even) {
background-color: lightgrey;
}

table td {
border: 1px solid lightgray;
}

#slide-1 table {
width: 100%;
}

#slide-1 table caption {
background-color: lightblue;
border: 1px solid #000;
}

#slide-2 table {
width: 100%;
}

#slide-2 table caption {
background-color: lightgreen;
border: 1px solid #000;
}

#slide-3 table {
width: 100%;
}

#slide-3 table caption {
background-color: lightyellow;
border: 1px solid #000;


}



$("tbody").sortable({
items: "> tr"
});

$(document).on("click", ".slideNavItem", function() {
var navID = $(this).attr('id');
console.log(navID);

var slideTo = $('#' + navID.split("_")[1]);
console.log(slideTo);
var inactiveElems = $("main").find(".slide.inactive").toggleClass("inactive");
var curActiveElem = $("main").find(".slide.active");
var wrapper = slideTo.closest("main");
console.log(wrapper);
var button = $(this);
var wrapperInlineStyles = wrapper.attr('styles');
if (wrapperInlineStyles === undefined) {
wrapperInlineStyles = ""
}

var elemPos = slideTo.offset().left;
console.log(elemPos);
var moveTo = (wrapper.offset().left) - (elemPos);
console.log(moveTo);

wrapper.css({
"transform": "translate(" + moveTo + "px, 0)",
"transition": "1s ease-in-out"
});
wrapper.one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend',
function(e) {

$("main").find(".slide.active").removeClass("active") // remove active class from old position
slideTo.addClass("active"); // add active classs to new position
$("main").find(".slide").not(".active").addClass("inactive"); // now add hide (add inactive class to)the other elemens
wrapper.css({
"transition": "none"
});
});
});

Answer

It's probably a problem with jQuery having trouble calculating position with static positioning and translate transform. One easy solution would be to set your main element to position absolute and apply the -16 translate you apply when returning home. Like this:

main {
  display: flex;
  width: 303%;
  position: absolute;
  transform: translateX(-16px)
}

http://codepen.io/anon/pen/bwqPqk