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?
Use of the preventDefault() or stopPropagation() method: This method prevents the event handler from responding to both touchstart and clicks events.
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.
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.
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:
Two events were fired, but you only get one on your Observable.
You can play around in this plunker
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 */});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With