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

Navigate back to the previous page upon form submission to a PHP file, with a div dynamically populated with targeted content

I'm facing a logic dilemma: I have a webpage with a div called #content, where I've embedded another page containing a form for submitting data* (there are other pages loaded into #content as well, but they are not active at the same time, one o ...

Incorporating a classList.toggle into a snippet of code

button, p, h1, h2, h3, h4, h5, a{ /* Define specific elements to use "fantasy" font */ font-family: Tahoma; } #main_body{ margin: 0px auto; background-color: #dedede; } #top_body{ /* Remove margin for simplicity */ } #t ...

Using AJAX and JQuery to automatically refresh a webpage on a scheduled interval

I am attempting to automatically refresh a page every 5 seconds with updated data from an SQL Server. Below is my code snippet: @model Test.Data.Domain.ManufacturingCdMachine @{ ViewBag.Title = "Rimage Details"; ViewBag.JobId = Model.CurrentManufa ...

Angular: Selecting all checkboxes outside of an ng-repeat loop

Project Overview In my project, there is a system for managing small product orders. Users have the ability to add order lines and attach one or more products to each order line. While it may be uncommon to have multiple products on the same order line, t ...

Tips for effectively utilizing Vuelidate to display errors selectively after the user has completed input:

I have implemented a form using Bootstrap-Vue with some Vuelidation code applied to it. <b-form @submit.prevent="onSubmit"> <input type="hidden" name="_token" :value="csrf" /> <transition-group name="fade"> <b-form ...

Unresponsive HTML button

I'm currently developing an interactive text-based game that relies on button functionality to change text content. Everything was functioning perfectly until just a few moments ago, but now it has inexplicably stopped working. Here is the section of ...

Steps for implementing target='_blank' on a <Link> tag with more than just an <a> element inside

I'm facing an issue where I need to open a new browser tab and redirect to a specific URL when a button is clicked. The problem arises when using an element other than an anchor tag inside the Next's <Link> element, as it seems to ignore th ...

Incorporating a node module into my Angularjs application

Recently, I stumbled upon a handful of modules that I would like to incorporate into my Angular app. However, I find myself at a crossroads on how to effectively integrate them into my project as I will need to use "require()" in my factory file. One part ...

Refreshing a Node.js server page upon receiving a JSON update

My web application serves as a monitoring interface for tracking changes in "objects" processed by the computer, specifically when they exceed a certain threshold. The Node Js server is running on the same machine and is responsible for displaying data in ...

Utilize a locally stored VueJs file rather than importing it from an external source

Starting my journey with VueJs using single file application has been quite interesting. Initially, I had everything in a single html page with both javascript and CSS styles embedded within it. To avoid fetching VueJs features online, I downloaded the V ...

Combining two arrays of objects in JSON files based on a shared key

Seeking assistance to merge two object arrays in JavaScript/jQuery based on a common key (code). These arrays are sourced from separate JSON files. I've provided shortened versions of the files as they are lengthy. Appreciate any help in advance. O ...

Troubleshooting issue with setting variables in Firefox's JavaScript

I have created a small JavaScript script that defines a value (referred to as stock), which I want to set as the maximum in a dropdown list. It will be set as the maximum value if it exceeds 6. Below is the code snippet: <script type="text/javascript" ...

What is the best way to consistently and frequently invoke a REST API in Angular 8 using RxJS?

I have developed a REST API that retrieves a list of values. My goal is to immediately invoke this API to fetch values and store them in a component's member variable. Subsequently, I plan to refresh the data every five minutes. Upon conducting some ...

Creating Your Own Image Hosting Website: Learn how to consistently display an HTML file with a specific image from the URL

I'm currently in the process of developing my own image hosting site at Everything is functioning as intended, but I am looking to make a change. Currently, when a shared image link is opened, it only displays the image. However, I would like it to ...

Convert a JSON object into a new format with a nested hierarchy

The JSON object below is currently formatted as follows: { "id": "jsonid", "attributes": { "personName": { "id": "name1", "group": "1.1" }, "ag ...

What is the process for configuring my CSS and JS files to send HTTP response headers?

During our security evaluation of a web application built in Laravel 4, we discovered that the Anti-MIME-Sniffing header X-Content-Type-Options was not properly configured to 'nosniff'. The following PHP code snippet sets the necessary HTTP heade ...

Condensing an Array of Objects into a solitary result

Hey there, I'm currently exploring the most efficient method to accomplish a task. The data I am dealing with looks something like this: [ { name: 'email.delivered', programme: 'Email One', timestamp: 2022-03-24T18: ...

Sending data in chunks using Vue.js

I'm interested in sending the data in chunks. Currently, what I send to the server looks like this: for loop - 1, 2, 3. However, the server receives it asynchronously as 3, 1, 2 and I need it to be received synchronously in the order of my for loop: 1 ...

Error encountered: The object 'Sys' is not defined in the Microsoft JScript runtime

I currently have a webpage with the following code snippet: <script type="text/javascript" language="javascript"> /// <reference name="MicrosoftAjax.js" /> Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler ...

Tips for transferring information from a child component to its parent using a click event in the parent component

My React application is designed to generate quizzes. The main component, <CreateQuiz/>, contains a child component called <QuestionForm/>. Additionally, within the <CreateQuiz/> component, there is a button labeled "Add Question" which a ...