Project Reflection: Mobile Touch Events
Last weekend, I spent more than 10 hours trying to figure out why my custom highlighting functionality was not working in iOS Simulator, yet worked perfectly in the browser. I did not find too many resources online, so I am writing this post in the hope that it may shed some light for others.
Until this point, I had written a series of functions that split one long string (a paragraph) into an array of strings (individual words), separated by whitespace. I recorded the first and last strings touched by a user, and applied a yellow background—a "highlight"—to the first string, last string, and all of the strings in between. The touch event fired continuously, and so as a user dragged his finger across the screen, the last string he touched updated continuously.
Everything worked accordingly in my Chrome browser. As soon as I launched it in iOS Simulator, though… nothing. The screen was totally unresponsive. I tried to fix it. I changed the touch event from a direct DOM handler to a directive. I tried all iterations of both touch events (touchstart, touchmove, and touchend) and drag events (dragstart, dragend). I wrote and rewrote functions, and posted in Stack Overflow as well as the Ionic Forum. I console.log-ged every line to try and isolate the problem. I read documentation for Ionic and Hammer.js (which powers touch events in Ionic).
One of the toughest parts about programming is figuring out what to look for in terms of help. My first Google search, “touch events ionic not working ios simulator,” garnered 190,000 results. (Interestingly enough, the first post for that search is now my unanswered Stack Overflow question.)
I tried to narrow my search. The search “event.target touch different web browser ios simulator ionic” led to 14,100 results.
As I researched the problem, a few things became clear. One, other people faced the same issue.
And two, few seemed to know what was going on under the hood.
At this point, I’m on hour eight or so and wanted to pull my hair out. What was going on?
I don’t remember the exact search terms I used, but I finally found clarity in three posts.
This first post explains the issue I was facing—when touching an HTML element and releasing on another element on mobile, the touch events’ target is the same HTML element in both cases. This is different than in the case with the desktop browser, where the target changes depending on which element is currently touched.
The user Aule provides this explanation: “The underlying events for touchstart and touchend both provide the element the touch started on as the event target. However, as Hammer emulates touches for mouse based events, it picks up the correct (in my opinion) target for the fake touchend event. Technically the problem is that the behavior is inconsistent as the touchend target is correct according to specification.”
This second post provides more supporting evidence, and a proposed solution. This third post offers a sound definition of the touch event target: “the DOM element that is the event target of the touch, even if the touch has moved outside of this element.”
Here’s what’s happening—as I move from a web browser to the iOS simulator, the touch events are interpreted differently. Rather than firing continuously and picking up the newest DOM element, they stay fixed on the element that’s first touched.
For the vast majority of the time, I assumed the problem was in my code. I thought I had written something incorrectly. What I didn’t realize was that my code was working exactly as it should. The problem was not with my code—it was with my understanding of how touch events are interpreted in a mobile environment.
I’m still working on it. Fortunately or not, my user research shows that users are split between these two preferred highlighting mechanisms.
- Long-press first word, then drag finger to last word. Markers appear on either end of the selection to make adjustments.
- Tap first word, tap last word. Selection in middle is highlighted.
I will go with the second route for now in order to stay within my project plan. Right now, I’m happy that I know what’s going on.
Have you encountered a similar problem before? How did you fix it? Leave your comments below.