-1

I have a swipe detection function detectswipe(el, func) that listens for data-animate="swipe" and runs the function swipe(el, d) when swiped on mobile. The problem is it only runs on the first instance of data-animate="swipe" and not every instance.

How do I change my code to run on every instance of data-animate="swipe"?

function detectswipe(el, func) {
  swipe_det = new Object();
  swipe_det.sX = 0;
  swipe_det.sY = 0;
  swipe_det.eX = 0;
  swipe_det.eY = 0;
  var min_x = 30; //min x swipe for horizontal swipe
  var max_x = 30; //max x difference for vertical swipe
  var min_y = 50; //min y swipe for vertical swipe
  var max_y = 60; //max y difference for horizontal swipe
  var direc = "";
  ele = document.querySelector(el);
  ele.addEventListener(
    "touchstart",
    function (e) {
      var t = e.touches[0];
      swipe_det.sX = t.screenX;
      swipe_det.sY = t.screenY;
    },
    false
  );
  ele.addEventListener(
    "touchmove",
    function (e) {
      e.preventDefault();
      var t = e.touches[0];
      swipe_det.eX = t.screenX;
      swipe_det.eY = t.screenY;
    },
    false
  );
  ele.addEventListener(
    "touchend",
    function (e) {
      //horizontal detection
      if (
        (swipe_det.eX - min_x > swipe_det.sX ||
          swipe_det.eX + min_x < swipe_det.sX) &&
        swipe_det.eY < swipe_det.sY + max_y &&
        swipe_det.sY > swipe_det.eY - max_y
      ) {
        if (swipe_det.eX > swipe_det.sX) direc = "r";
        else direc = "l";
      }
      //vertical detection
      if (
        (swipe_det.eY - min_y > swipe_det.sY ||
          swipe_det.eY + min_y < swipe_det.sY) &&
        swipe_det.eX < swipe_det.sX + max_x &&
        swipe_det.sX > swipe_det.eX - max_x
      ) {
        if (swipe_det.eY > swipe_det.sY) direc = "d";
        else direc = "u";
      }

      if (direc != "") {
        if (typeof func == "function") func(el, direc);
      }
      direc = "";
    },
    false
  );
}

function swipe(el, d) {
  $(el).addClass("active");
}

detectswipe("[data-animate='swipe']", swipe);
body {
  display: flex
}
.item {
  margin: 2.3rem;
  height: 100px;
  width: 100px;
  background: orange
}
.item.active {
  background: green
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="item" data-animate="swipe"></div>
<div class="item" data-animate="swipe"></div>
Kyle Underhill
  • 89
  • 15
  • 43
  • `ele = document.querySelectorAll(el);` will select all elements `querySelector` only the first. – Jon P Feb 14 '22 at 21:35
  • This is mentioned in the [documentation](//developer.mozilla.org/docs/Web/API/Document/querySelector#return_value). Familiarize yourself with the [DOM API](//developer.mozilla.org/docs/Web/API/Document_Object_Model). – Sebastian Simon Feb 14 '22 at 21:39
  • Does this answer your question? [What do querySelectorAll and getElementsBy\* methods return?](https://stackoverflow.com/questions/10693845/what-do-queryselectorall-and-getelementsby-methods-return). I'm sure there is a closer duplicate around here somewhere. – Jon P Feb 14 '22 at 21:40
  • 1
    Use [event delegation](//developer.mozilla.org/docs/Learn/JavaScript/Building_blocks/Events#Event_delegation) instead of adding several event listeners — it’s more maintainable and applies to dynamically added elements. See [the tag info](/tags/event-delegation/info) and [this Q&A](/q/1687296/4642212). Use the [event argument](//developer.mozilla.org/docs/Web/API/EventTarget/addEventListener#The_event_listener_callback): `theRoot.addEventListener("touchend", ({` [`target`](//developer.mozilla.org/docs/Web/API/Event/target) `}) => { const elem = target.closest(theSelector); if(elem){`…`} });`. – Sebastian Simon Feb 14 '22 at 21:41
  • I tried `ele = document.querySelectorAll.forEach(el);` to select each instance of the element but it didn't work – Kyle Underhill Feb 14 '22 at 21:58
  • Also tried `detectswipe.forEach("[data-animate='swipe']", swipe);` – Kyle Underhill Feb 14 '22 at 22:01

1 Answers1

1

To boil it down to the basics:

function detectswipe(el, func) {
  /*Your stuff here*/
 
  /*Get all the elements*/
  ele = document.querySelectorAll(el);
  /*Iterate the elements*/
  ele.forEach(function(item){
     /*Add the event listeners*/
     item.addEventListener("touchstart", function(e){/*your stuff*/});
     item.addEventListener("touchmove", function(e){/*your stuff*/});
     /*etc*/
  });
}

Event delegation could also work here but we don't know much about the structure of your document.

Jon P
  • 19,442
  • 8
  • 49
  • 72
  • I tried adding the code to your example but perhaps I missed a step as it isn't working https://codepen.io/moofawsaw/pen/jOaGBKq – Kyle Underhill Feb 15 '22 at 00:12
  • Try resetting the `swipe_det ` object in the `touchstart` handler. Otherwise, it will still be in the same state as at the end of the previous touch event. – Jon P Feb 15 '22 at 00:17
  • Sorry about that, after all that talk of `querySelectorAll` , I went and used `querySelector`. Try now. – Jon P Feb 15 '22 at 00:21