3

I am trying to set up the following page where:

  1. If you click the button, you can see a div.
  2. If you click the div, you can see the next div.
  3. If you move the button, there is no »click« (desired behaviour)

The problem I am having is that if you move the div, the next div appears - this is not what I want. The "next div" should not be displayed after a drag event finishes on it.

Here is my code:

$(function() {
  $("#button").draggable({
    stack: 'div',
    containment: "body"
  });
});

$('#button').on('mouseup', function() {
  if (!$(this).hasClass('ui-draggable-dragging')) {
    // click function
    $("#content").toggle();
  }
});

$(function() {
  $("#content").draggable({
    stack: 'div',
    containment: "body"
  });
});

let containers = $('.trip').hide();
let firstContainer = containers.first().show();

containers.on('click', function() {
  //Get current element and next sibling
  let elem = $(this);
  let next = elem.next('.trip');

  //Does sibling exist?
  if (next.length) {
    next.show();
  } else {
    firstContainer.show();
  }
  elem.hide();
});
body {
  width: 100vw;
  height: 100vh;
  padding: 0;
  margin: 0;
  left: 0;
  top: 0;
  background-color: grey;
}

#button {
  width: 100px;
  height: 100px;
  background-color: cyan;
}

#content {
  display: none;
  cursor: all-scroll;
  top: 10%;
  left: 10%;
  position: absolute;
}

.trip {
  width: 200px;
  height: 200px;
  background-color: blue;
  color: white;
}
<div id="button">Button</div>

<div id="content">
  <div class="trip">div 1</div>
  <div class="trip">div 2</div>
  <div class="trip">div 3</div>
</div>

<script src="https://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="https://code.jquery.com/ui/1.8.21/jquery-ui.min.js"></script>
<script src="https://raw.githubusercontent.com/furf/jquery-ui-touch-punch/master/jquery.ui.touch-punch.min.js"></script>

Is there a way to solve this? :)
(a possible problem is also that pure JavaScript is mixed with jQuery)
Thanks

Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313

2 Answers2

1

The main problem to solve here is in distinguishing a regular click event on #content, from other "click like events" that are also triggered during completion of the element being dragged.

You're code currently has a method of doing that which you could re purpose for the desired behaviour:

if (! $(this).hasClass('ui-draggable-dragging')) {
   /* This was a "regular click event"
}

So in the case of your code, you could revise it as follows:

$(function() {

  /* Combine on ready logic into one place */

  $("#button").draggable({
    stack: 'div',
    containment: "body"
  });
  
  $("#content").draggable({
    stack: 'div',
    containment: "body"
  });
  
  /* Hide all trip elements except for first */
  $('.trip', '#content').not(':first').hide();
});

$('#button').on('mouseup', function() {
  if (!$(this).hasClass('ui-draggable-dragging')) {
    $("#content").toggle();
  }
});

$('#content').on('mouseup', function() {

  /* Reuse same logic in #button mouseup handler */
  if (!$(this).hasClass('ui-draggable-dragging')) {

      /* 
      If content element if not dragging, treat mouse up as conclusion
      of click event and rotate visibility of trip elements like this
      */
      let trip = $('.trip:visible', '#content');
      let next = trip.next().length === 0 ? 
          $('.trip:first', '#content') : trip.next();
      
      trip.hide();
      next.show(); 
  }
});
body {
  width: 100vw;
  height: 100vh;
  padding: 0;
  margin: 0;
  left: 0;
  top: 0;
  background-color: grey;
}

#button {
  width: 100px;
  height: 100px;
  background-color: cyan;
}

#content {
  display: none;
  cursor: all-scroll;
  top: 10%;
  left: 10%;
  position: absolute;
}

.trip {
  width: 200px;
  height: 200px;
  background-color: blue;
  color: white;
}
<div id="button">Button</div>

<div id="content">
  <div class="trip">div 1</div>
  <div class="trip">div 2</div>
  <div class="trip">div 3</div>
</div>

<script src="https://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="https://code.jquery.com/ui/1.8.21/jquery-ui.min.js"></script>
<script src="https://raw.githubusercontent.com/furf/jquery-ui-touch-punch/master/jquery.ui.touch-punch.min.js"></script>
Dacre Denny
  • 29,664
  • 5
  • 45
  • 65
  • `"Uncaught SyntaxError: missing ) after argument list"` consider fixing that so we could use the live demo, thanks. – ThS Aug 04 '19 at 23:49
  • @DacreDenny I have tears in my eyes! Thank you sooooooo much! One last question: Does that draggable thing work on mobile phones too? – Lina McClanahan Aug 04 '19 at 23:57
  • @DacreDenny Ok, I checked it: It does not work. Why? :( – Lina McClanahan Aug 04 '19 at 23:59
  • @LinaMcClanahan you're welcome - glad I could help :) mobile phones may be a little tricky - let me know if this works for you on mobile as is - if not I can try help you further :) – Dacre Denny Aug 04 '19 at 23:59
  • @LinaMcClanahan it seems like there is limited support for mobile with jqueryui however I found this which seems to work better on mobile - would it be an option for you? https://www.jqueryscript.net/other/Mobile-Drag-Drop-Plugin-jQuery.html – Dacre Denny Aug 05 '19 at 00:08
  • @DacreDenny Ahhhh now I figured it out: The jquery.ui.touch-punch.min.js has to be uploaded directly to the server. I don't know why, but then it works. Wish you all the best. Actually you live in New Zealand? You have all the best! :) ;) – Lina McClanahan Aug 05 '19 at 00:08
  • @DacreDenny Same moment! :D Hm. What would you recommend? – Lina McClanahan Aug 05 '19 at 00:09
  • @LinaMcClanahan hi again - if jqueryui is working for you on mobile I'd probably stick with that as there's wider community support for it. I'm in New Zealand, for now at least :-) – Dacre Denny Aug 05 '19 at 00:11
  • @DacreDenny Say Hi to the Kiwis from mee! :D Thank you and have a nice day – Lina McClanahan Aug 05 '19 at 00:15
  • @LinaMcClanahan haha they're pretty hard to find but will do - all the best with your project :-) – Dacre Denny Aug 05 '19 at 00:16
  • @DacreDenny May I ask you another question, Kiwi neighbor? I have now three buttons with different content. In principle, it works. But I have z-index problems. The last object in the code is always on top. But the last clicked or moved object should be on top. Do you know how to do that? – Lina McClanahan Aug 05 '19 at 00:38
  • Yep, it will probably involves a bit of extra css and extension to your script - if you would like to send me a link to a new question for this problem I'll be happy to help :) – Dacre Denny Aug 05 '19 at 00:43
  • @DacreDenny I tried to minify the code and was a bit slow, sorry! Here is the link: https://stackoverflow.com/questions/57351370/i-have-a-z-index-problem-with-draggable-divs – Lina McClanahan Aug 05 '19 at 01:45
  • @LinaMcClanahan just posted this for you: https://stackoverflow.com/a/57351542/8526705 hope that helps! – Dacre Denny Aug 05 '19 at 02:22
1

Actually, all you need is this bit of readable code,

  • Assign a class .draggable to all your draggable elements
  • Use the new class as stack: '.draggable'
  • Register click to your '#container', not on your .trip elements
  • Use only one Event, the "click" one:
  • Hide all .trip but first using CSS .trip~.trip {display:none;}

jQuery( $ => {

  const $cont = $('#content');
  const $bttn = $('#button');
  const $trip = $('.trip');
  const tripL = $trip.length;
  let   i = 0;

  $('.draggable').draggable({stack:'div', containment:'body'});
  
  $bttn.on('click', function() {
    if (!$(this).hasClass('ui-draggable-dragging')) $cont.toggle();
  });

  $cont.on('click', function() {
    $trip.eq(++i % tripL).show().siblings($trip).hide();
  });

});
html, body { height:100%; margin:0;}

body {
  background-color: grey;
}

#button {
  width: 100px;
  height: 100px;
  background-color: cyan;
}

#content {
  display: none;
  cursor: all-scroll;
  top: 10%;
  left: 10%;
  position: absolute;
}

.trip {
  width: 200px;
  height: 200px;
  background-color: blue;
  color: white;
}

.trip ~ .trip {display: none;}
<!-- PS: Add class="draggable" to draggable elements -->

<div id="button" class="draggable">Button</div>
<div id="content" class="draggable">
  <div class="trip" id="a">div 1</div>
  <div class="trip" id="b">div 2</div>
  <div class="trip" id="c">div 3</div>
</div>

<script src="https://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="https://code.jquery.com/ui/1.8.21/jquery-ui.min.js"></script>
<script src="https://raw.githubusercontent.com/furf/jquery-ui-touch-punch/master/jquery.ui.touch-punch.min.js"></script>

EDIT

For more contents see this answer: https://stackoverflow.com/a/57351517/383904

Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
  • Hey, thank you for your answer. The last moved or clicked object should always be on top. Is that possible with your code? – Lina McClanahan Aug 05 '19 at 00:39
  • @LinaMcClanahan Sure, I removed accidentally the `stack:'div',` that handles the z-index. I've added it back :) – Roko C. Buljan Aug 05 '19 at 01:08
  • Ok, interesting! Would that solve my »new problem« too? Link: https://stackoverflow.com/questions/57351370/i-have-a-z-index-problem-with-draggable-divs – Lina McClanahan Aug 05 '19 at 01:46