Preventing Click Events from Firing During Drag in JavaScript

I have implemented a code for dragging containers left or right, which is functioning properly. Users can also click on the "thumb". However, I am facing an issue where a click event occurs even after dragging. I want to ensure that only either drag or click event happens. How can I separate these events? Additionally, it needs to be compatible with tablets as well.

var thumbContainer = document.querySelector('.aplbox-thumb-container'),
  thumbContainerWrap = document.querySelector('.aplbox-thumb-container-wrap'),
  startXThumb,
  startTouchThumb

if ("ontouchstart" in window) {
  thumbContainer.addEventListener("touchstart", dragStartThumb);
}
thumbContainer.addEventListener("mousedown", dragStartThumb);

function dragStartThumb(e) {

  if (e.preventDefault) e.preventDefault();
  e.stopPropagation()

  if (!startTouchThumb) {
    startTouchThumb = true;

    document.addEventListener('mousemove', dragMoveThumb)
    document.addEventListener('mouseup', dragEndThumb);

    if ("ontouchstart" in window) {
      document.addEventListener('touchmove', dragMoveThumb)
      document.addEventListener('touchend', dragEndThumb);
    }

    var point;
    if (e.type == 'touchstart') {
      var touches = e.changedTouches;

      if (touches.length > 1) {
        return false;
      }
      point = touches[0];
      e.preventDefault();
    } else {
      point = e;
      e.preventDefault();
    }

    var currX = thumbContainer.style.transform.replace(/[^\d.]/g, '');
    currX = parseInt(currX) || 0;

    startXThumb = point.pageX + currX;

  }

}

function dragMoveThumb(e) {
  if (startTouchThumb) {

    var point;
    if (e.type == 'touchmove') {
      var touches = e.changedTouches;

      if (touches.length > 1) {
        return false;
      }
      point = touches[0];
      e.preventDefault();
    } else {
      point = e;
      e.preventDefault();
    }

    var diff = point.pageX - startXThumb;

    if (diff > 0) diff = 0;
    else if (diff < -thumbContainer.offsetWidth + thumbContainerWrap.offsetWidth) diff = -thumbContainer.offsetWidth + thumbContainerWrap.offsetWidth;

    thumbContainer.style.transform = 'translateX(' + diff + 'px)';

  }

}

function dragEndThumb(e) {

  e.stopPropagation()

  if (startTouchThumb) {
    startTouchThumb = false;

    document.removeEventListener('mousemove', dragMoveThumb)
    document.removeEventListener('mouseup', dragEndThumb);

    if ("ontouchstart" in window) {
      document.removeEventListener('touchmove', dragMoveThumb)
      document.removeEventListener('touchend', dragEndThumb);
    }

  }
}

//click thumb
thumbContainerWrap.addEventListener('click', function(e) {


  if (e.target.closest('.aplbox-thumb')) {


    console.log('click')

  }

})
.aplbox-thumb-container-wrap {
  position: absolute;
  top: 0;
  left: 0;
  background-color: #ccc;
  width: 100%;
  height: 100px;
  overflow: hidden;
  box-sizing: border-box;
}

.aplbox-thumb-container {
  position: relative;
  padding: 5px 0;
  height: 100%;
  display: flex;
  flex-direction: row;
  transform: translateX(0);
  touch-action: none;
}

.aplbox-thumb {
  width: 100px;
  height: 70px;
  margin-right: 5px;
  box-sizing: border-box;
  background: #333;
  flex-shrink: 0;
  overflow: hidden;
  margin-bottom: 5px;
}
<div class="aplbox-thumb-container-wrap">
  <div class="aplbox-thumb-container" style="width: 1300px;">
    <div class="aplbox-thumb" data-id="0"></div>
    <div class="aplbox-thumb" data-id="1"></div>
    <div class="aplbox-thumb" data-id="2"></div>
    <div class="aplbox-thumb" data-id="3"></div>
    <div class="aplbox-thumb" data-id="4"></div>
    <div class="aplbox-thumb" data-id="5"></div>
    <div class="aplbox-thumb" data-id="6"></div>
    <div class="aplbox-thumb" data-id="7"></div>
    <div class="aplbox-thumb" data-id="8"></div>
    <div class="aplbox-thumb" data-id="9"></div>
    <div class="aplbox-thumb" data-id="10"></div>
    <div class="aplbox-thumb" data-id="11"></div>
  </div>
</div>

Answer №1

Define a variable called moved. Within the dragStartThumb function, set this variable to false. Then, in the dragMoveThumb function, set it to true. Finally, in the onclick event, check the value of this variable as shown below:
Similar to what @Amirhoseinh73 suggested, instead of setting the flag to true in the touchend function, we should set it to true in the mousemove function to ensure that the variable is not always set to true.

var thumbContainer = document.querySelector('.aplbox-thumb-container'),
  thumbContainerWrap = document.querySelector('.aplbox-thumb-container-wrap'),
  startXThumb,
  startTouchThumb
  
let moved = false;

if ("ontouchstart" in window) {
      thumbContainer.addEventListener("touchstart", dragStartThumb);
}
    
thumbContainer.addEventListener("mousedown", dragStartThumb);


function dragStartThumb(e) {
   moved = false;
   
  //if (e.preventDefault) e.preventDefault();
  e.stopPropagation()

  if (!startTouchThumb) {
    startTouchThumb = true;

    document.addEventListener('mousemove', dragMoveThumb)
    document.addEventListener('mouseup', dragEndThumb);

    if ("ontouchstart" in window) {
      document.addEventListener('touchmove', dragMoveThumb)
      document.addEventListener('touchend', dragEndThumb);
    }

    var point;
    if (e.type == 'touchstart') {
      var touches = e.changedTouches;

      if (touches.length > 1) {
        return false;
      }
      point = touches[0];
      //e.preventDefault();
    } else {
      point = e;
      //e.preventDefault();
    }

    var currX = thumbContainer.style.transform.replace(/[^\d.]/g, '');
    currX = parseInt(currX) || 0;

    startXThumb = point.pageX + currX;

  }

}

function dragMoveThumb(e) {
  moved = true;
    
  if (startTouchThumb) {

    var point;
    if (e.type == 'touchmove') {
      var touches = e.changedTouches;

      if (touches.length > 1) {
        return false;
      }
      point = touches[0];
      e.preventDefault();
    } else {
      point = e;
      e.preventDefault();
    }

    var diff = point.pageX - startXThumb;

    if (diff > 0) diff = 0;
    else if (diff < -thumbContainer.offsetWidth + thumbContainerWrap.offsetWidth) diff = -thumbContainer.offsetWidth + thumbContainerWrap.offsetWidth;

    thumbContainer.style.transform = 'translateX(' + diff + 'px)';

  }

}

function dragEndThumb(e) {
e.stopPropagation()
  if (startTouchThumb) {
    startTouchThumb = false;

    document.removeEventListener('mousemove', dragMoveThumb)
    document.removeEventListener('mouseup', dragEndThumb);

    if ("ontouchstart" in window) {
      document.removeEventListener('touchmove', dragMoveThumb)
      document.removeEventListener('touchend', dragEndThumb);
    }

  }
}

//click thumb
thumbContainerWrap.addEventListener('click', function(e) {
  if (e.target.closest('.aplbox-thumb') && !moved) {

    console.log('click')

  }

})
.aplbox-thumb-container-wrap {
  position: absolute;
  top: 0;
  left: 0;
  background-color: #ccc;
  width: 100%;
  height: 100px;
  overflow: hidden;
  box-sizing: border-box;
}

.aplbox-thumb-container {
  position: relative;
  padding: 5px 0;
  height: 100%;
  display: flex;
  flex-direction: row;
  transform: translateX(0);
  touch-action: none;
}

.aplbox-thumb {
  width: 100px;
  height: 70px;
  margin-right: 5px;
  box-sizing: border-box;
  background: #333;
  flex-shrink: 0;
  overflow: hidden;
  margin-bottom: 5px;
}
<div class="aplbox-thumb-container-wrap">
  <div class="aplbox-thumb-container" style="width: 1300px;">
    <div class="aplbox-thumb" data-id="0"></div>
    <div class="aplbox-thumb" data-id="1"></div>
    <div class="aplbox-thumb" data-id="2"></div>
    <div class="aplbox-thumb" data-id="3"></div>
    <div class="aplbox-thumb" data-id="4"></div>
    <div class="aplbox-thumb" data-id="5"></div>
    <div class="aplbox-thumb" data-id="6"></div>
    <div class="aplbox-thumb" data-id="7"></div>
    <div class="aplbox-thumb" data-id="8"></div>
    <div class="aplbox-thumb" data-id="9"></div>
    <div class="aplbox-thumb" data-id="10"></div>
    <div class="aplbox-thumb" data-id="11"></div>
  </div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to receive both errors and warnings for the same ESLint rule?

My team is currently in the process of refactoring our codebase, utilizing ESLint to pinpoint any lint errors within our files. Initially, we set high thresholds in one .eslintrc file and have been gradually decreasing these limits as we enhance specific f ...

Display Email content within a bootstrap modal using CSS styling

Is there a way to prevent CSS from overwriting tags on my original page when loading an email body into a modal via ajax call? The email body has its own CSS styles that are affecting the layout of my current page. I've considered renaming all the tag ...

Textarea malfunctions if it includes HTML code

Here's a situation I'm facing. I'm setting up a basic text area with buttons for bold, link, img, and italics. When I enter plain text in the text area, everything works fine and the method is triggered as expected. But when I include HTML ...

Why does the response.json() method in the Fetch API return a JavaScript object instead of a JSON string?

After using Body.json() to read the response stream and parse it as JSON, I expected to receive a JSON string when I logged the jsonData. Instead, I received a Javascript object. Shouldn't jsonData return a JSON string until we call JSON.parse() to co ...

The design I created includes a horizontal scroll feature and certain elements are not properly aligned in the

Oh man, I'm really frustrated right now. I want all my elements to be centered horizontally on smaller devices, but some of them are slightly off to the side. And to top it off, there's a horizontal scroll appearing - it's like something is ...

Ensure $q.all does not produce an error when one promise is not resolved

While geocoding addresses, there are instances where some fail. My goal is to retrieve the successful results and disregard the failed ones in order to display the coordinates on a map. Currently, using $q.all triggers the errorHandler when one promise i ...

Tips for aligning 2 divs in the same position?

I am working on a slider feature that includes both videos and pictures. I need to ensure that the videos are hidden when the device width exceeds 600px. Here is the HTML code snippet: <video class="player__video" width="506" height="506" muted preloa ...

What is the best way to create an optional object parameter in Typescript?

I'm working on a function that looks like this: const func = (arg1: string, { objArg = true }:{ objArg: string }) => { // some code } Is it possible to make the second parameter (an object) optional? ...

Is there a way for me to incorporate a feature that verifies whether an email address is already registered before allowing the person to sign up?

I am currently working with Node.js, express.js, mongoose, and pug to develop a registration/login system. I have successfully stored the name and email in a mongoose database with specified schema for these fields. The data is sent from a pug page via a p ...

ReactJS state refuses to update

In my FreeCodeCamp leaderboard table, I have implemented functionality where clicking on the highlighted table header calls different URLs based on sorting criteria. The application either calls https://fcctop100.herokuapp.com/api/fccusers/top/recent or ht ...

Traverse through JSON data using jQuery

Currently, I have a JSON response that I am uncertain how to effectively iterate through and utilize. { "ID": 1, "Name": "dept1", "Categories": [ { "ID": 1, "Name": "catg1" }, { "ID": 2, "Name": "catg2" } ] ...

What is the best way to eliminate excessive margin-bottom on a floating image?

Is it possible to maintain the same margin at the right and bottom of an image when using <img> inside <p><img style="float:left">dummy text dummy text dummy text dummy text</p>? ...

What is the best method for interpreting XML using JavaScript?

I am facing a challenge with fetching and parsing an XML file using JavaScript. The XML-file is beyond my control. Recently, there has been a change in the encoding of some XML files which prevents the code from being parsed successfully. Previously it wa ...

Display error page when unable to load ng-view template

Is there a way to display a standard error page or template if a certain template cannot be loaded using ngRoute in Angular? I've come across suggestions that subscribing to the $routeChangeError event might help, but I'm not sure what steps to ...

If the URL matches a specific path, then append a parameter

I've created a script that adds a parameter to a URL based on specific subfolders. For example, if the URL contains /de, it will add ?_sft_language=german. However, I'm encountering an issue where the code is running multiple times instead of jus ...

What is the method to modify an action in an Ajax function?

I am trying to modify the action in the AjaxUpload function. The issue is that the value of setnamefile in the action does not change because the page does not reload. My idea was to change the action on submit, but I have not been able to do so successfu ...

Navigate through chosen options by clicking on a button

It's a new day and I'm facing a simple challenge that seems complicated in the morning haze. I need to create a select dropdown with zoom percentage values, along with + and - buttons to navigate through the list. If I have the following setup: ...

The jQuery .load function does not function properly when an ajax query is already underway

My web application utilizes dynamic loading of content within the same div (.content) through either an ajax request or a .load() request. An example of the ajax request code snippet is: $(document).on('click', '.button1', functio ...

CSS Code Failing to Adjust Inner Components Width in Variable Table

I'm facing an issue while trying to create an excel-style table using HTML and CSS. The problem arises when I attempt to have a varying number of columns in different rows, as the table exceeds the border limit and expands on its own. My goal is to re ...

Deciphering HTML encoding for text fields

As I transition from the Microsoft stack, specifically WPF, to HTML5, I apologize for any beginner-level questions. Today's topic is HTML encoding and decoding. Imagine an HTML5 application making AJAX calls to a C# backend using HTTP. The server al ...