Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle hybrid devices in click/touch events properly?

I'm trying to find out how to work with hybrid devices when it comes to binding touch and click events, but I can't find any solution that actually seems to work (I haven't got a hybrid device so I cannot test directly but since the failed attempts doesn't even work on normal devices I assume they don't work on a hybrid device either).

The problem is that on a hybrid device you have to cover both touch and click events without firing the functions twice. So if you look at my failed attempts (2 and 3) you can see that I bind to both touchend and click, but there appears to be some sort of syntax error or something because this causes none of the events to actually fire.

The first solution works fine but that's when I'm just using one or the other of the event firing types.

What I've tried so far:

1 - Works on touch devices and click devices:

_renderer.listenGlobal('document', 'ontouchstart' in window ? 'touchend' : 'click', (e) => {

  console.log('works');  
});

2 - Doesn't fire on either touch or click devices:

_renderer.listenGlobal('document', 'touchend click', (e) => {

  console.log('works');

  e.stopPropagation(); 
});

3 - Doesn't fire on either touch or click devices:

_renderer.listenGlobal('document', 'touchend, click', (e) => {

  console.log('works');  

  e.stopPropagation();
});

As you can see the first example covers 2/3 device types, while the other ones cover 0.

How can I make sure that my functions will run properly on every device?

like image 655
Chrillewoodz Avatar asked Oct 08 '16 09:10

Chrillewoodz


People also ask

How do you bind Touchstart and click events but not respond to both?

Use of the preventDefault() or stopPropagation() method: This method prevents the event handler from responding to both touchstart and clicks events.

What is the use of Touch_move?

Definition and Usage The touchmove event occurs when the user moves the finger across the screen. The touchmove event will be triggered once for each movement, and will continue to be triggered until the finger is released. Note: The touchmove event will only work on devices with a touch screen.

Does touch trigger click event?

Because mobile browsers should also work with with web applications that were build for mouse devices, touch devices also fire classic mouse events like mousedown or click . When a user follows a link on a touch device, the following events will be fired in sequence: touchstart.


2 Answers

You could use a Subject and debounce for a couple of milliseconds so you only have one event, something like this:

import {Component, Renderer} from '@angular/core'
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/debounceTime';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
    </div>
  `,
})
export class App {
  name = 'Angular2';
  subject = new Subject();
  
  constructor(renderer: Renderer) {
    renderer.listenGlobal('document', 'touchend', (e) => {
      console.log('touchend');
      this.subject.next(e);
    });
    renderer.listenGlobal('document', 'click', (e) => {
      console.log('click');
      this.subject.next(e);
    });

    this.subject.debounceTime(100).subscribe(event => {
      console.log(event); //do stuff here
    })
  }
}

So when you use hybrid devices, you will get this: enter image description here

Two events were fired, but you only get one on your Observable.

You can play around in this plunker

like image 57
Fabio Antunes Avatar answered Oct 27 '22 10:10

Fabio Antunes


Just add (tap) directive instead of (click) directive on your components and add hammerjs to your index.html file.

Angular 2 will do all the job for you.

Example:

<my-component (tap)="doSomething()"></my-component>

On your index.html add:

<script src="hammer.min.js"></script>

To get hammerjs

npm install hammerjs --save

With this the click and the tap will work fine. If you want to have more control over the tap or you want to bind events to your element on runtime try something like this.

_hammerEvents: HammerManager;

public bindTapEvent(element: ElementRef):void{
    this._hammerEvents = new Hammer(element.nativeElement);
    this._hammerEvents.on("tap", (event:any) => { /* do something */});
}
like image 26
dlcardozo Avatar answered Oct 27 '22 10:10

dlcardozo