12

I am searching on many forums and questions, but nobody seems to ask how to double click ou double tap in Angular/ionic 2 ?

In ionic v1 it was available with on-double-tap (see http://ionicframework.com/docs/api/directive/onDoubleTap/)

Does anyone maybe have a tip or any code to catch double click events on ionic 2 / angular 2?

Maybe through HammerJS?

Thank you very much ! Luis :)

luiswill
  • 952
  • 1
  • 11
  • 21

6 Answers6

25

So after 1-2 hours it was obvious, you don't need to catch double click events with Ionic, but with pure JavaScript: dblclick()

So in Angular 2 it would be: (dblclick)="myFunction()" and that's it!

Here you will find other events for JavaScript.

fscheidl
  • 2,281
  • 3
  • 19
  • 33
luiswill
  • 952
  • 1
  • 11
  • 21
  • Inorder for a generic implementation irrespective of the platform we need to write a custom directive of our own. – leox Mar 20 '19 at 05:43
7

html file

<button (tap)="tapEvent()">Tap Me!</button>

ts file

let count : number = 0;
tapEvent(){
this.count++;
setTimeout(() => {
  if (this.count == 1) {
    this.count = 0;
    alert('Single Tap');
  }if(this.count > 1){
    this.count = 0;
    alert('Double Tap');
  }
}, 250);

}

3

To catch the double click event, the following can be used:

(dblclick)="clickFunction()"

If we want to fire a function on click and onother function on double click we can use the following:

<button (click)="simpleClickFunction()" (dblclick)="doubleClickFunction()">click me!</button>

However, the simpleClickFunction function will be called also when doubleClickFunction is fired. To prevent it to happen, setTimeout can help as the following:

html template

<button (click)="simpleClickFunction()" (dblclick)="doubleClickFunction()">click me!</button>

Component

simpleClickFunction(): void{
    this.timer = 0;
    this.preventSimpleClick = false;
    let delay = 200;

    this.timer = setTimeout(() => {
      if(!this.preventSimpleClick){
        //whatever you want with simple click go here
        console.log("simple click");
      }
    }, delay);

  }

  doubleClickFunction(): void{
    this.preventSimpleClick = true;
    clearTimeout(this.timer);
    //whatever you want with double click go here
    console.log("double click");
  }
edkeveked
  • 17,989
  • 10
  • 55
  • 93
  • Could the one who downvoted the question please explain why ? – edkeveked Apr 07 '19 at 16:58
  • I'm not the one who downvoted, but I guess it's because your answer doesn't add anything to the other answers and also because it's not addressing the major issue of multi platform compatibility. But again, it's just a guess. – Edoardoo Sep 26 '19 at 15:03
  • The answer has been upvoted by others. So the answer is useful for others – edkeveked Sep 26 '19 at 15:42
1

So.

  1. dbclick isn't working on smartphone.
  2. Using a library is actually the way to go

I found the solution on this gitHub repo

Directive

import { Directive, EventEmitter, Output, OnInit, HostListener } from '@angular/core';

@Directive({
  selector: '[appTap]'
})
export class TapDirective implements OnInit {

  @Output() tap = new EventEmitter();
  @Output() doubleTap = new EventEmitter();
  lastTap = 0;
  tapCount = 0;
  tapTimeout = null;
  tapGesture = {
    name: 'tap',
    enabled: false,
    interval: 250,
  };
  doubleTapGesture = {
    name: 'doubleTap',
    enabled: false,
    interval: 300,
  };

  constructor() { }

  ngOnInit(): void {
    this.tapGesture.enabled = true;
    this.doubleTapGesture.enabled = true;
  }

  @HostListener('click', ['$event'])
  handleTaps(e) {
    const tapTimestamp = Math.floor(e.timeStamp);
    const isDoubleTap = this.lastTap + this.tapGesture.interval > tapTimestamp;
    if (!this.tapGesture.enabled && !this.doubleTapGesture.enabled) {
      return this.resetTaps();
    }
    this.tapCount++;
    if (isDoubleTap && this.doubleTapGesture.enabled) {
      this.emitTaps();
    } else if (!isDoubleTap) {
      this.tapTimeout = setTimeout(() => this.emitTaps(), this.tapGesture.interval);
    }
    this.lastTap = tapTimestamp;
  }

  private emitTaps() {
    if (this.tapCount === 1 && this.tapGesture.enabled) {
      this.tap.emit();
    } else if (this.tapCount === 2 && this.doubleTapGesture.enabled) {
      this.doubleTap.emit();
    }
    this.resetTaps();
  }

  private resetTaps() {
    clearTimeout(this.tapTimeout); // clear the old timeout
    this.tapCount = 0;
    this.tapTimeout = null;
    this.lastTap = 0;
  }

}

Module

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TapDirective } from './tap/tap.directive';
import { PressDirective } from './press/press.directive';
import { SwipeDirective } from './swipe/swipe.directive';
import { GestureDirective } from './gesture/gesture.directive';

@NgModule({
  declarations: [
    TapDirective,
  ],
  imports: [
    CommonModule
  ],
  exports: [
    TapDirective,
  ]
})
export class TapDirectiveModule { }
<div appTap (doubleTap)="doSomething()"

There you go..

Tips: I did let the tap logic, remove it if not needed

Raphaël Balet
  • 6,334
  • 6
  • 41
  • 78
  • This is pretty good. One thing, it could be improved by adding `@Input() mobileOnly: 'true' | 'false' | boolean = false;`, and a check if `Event instanceof PointerEvent` :) – Ron Strauss Aug 27 '23 at 08:45
0

Ionic 2 has basic gestures which can be accessed from HTML. Should work on iOS and Android. You can find the documentation here.

The source code provided by them is here.

Borja Perez
  • 3
  • 1
  • 7
0

For capturing generic gesture, I created the following to handle double click, long press and short swipe and release.

Make sure to import the GestureController from Ionic Angular

longPressStartedTime;

constructor(
        private gestureController: GestureController,
        ) { }

Create a class on the elements we want to attach the gesture handling to

<div class="long-pressable">
some content here...
</div>

Then create the gesture handling code handler

   let pressableElements = this.elementRef.nativeElement.querySelectorAll('.long-pressable') as any[];

    for(let i = 0; i < pressableElements.length; i++) {
      const gesture = this.gestureController.create({
        el: pressableElements[i],
        gestureName: 'long-press',
        threshold: 0,
        onStart: ev => {

          // double click
          if(this.longPressStartedTime && ((new Date().getTime() - this.longPressStartedTime) < 300)) {
            this.doubleClickMessage(this.chatMessages[i]);
          }
          this.longPressStartedTime = new Date().getTime();
          console.log("start")
        },
        onMove: ev => {
          //console.log("move", ev);
          if(ev.deltaX > 0 && ev.deltaX < 40) {
            pressableElements[i].style.transform = `translateX(${ev.deltaX}px)`;
          }
        },        
        onEnd: ev => {
          let longPressEllapsed = new Date().getTime() - this.longPressStartedTime;
          console.log("long press ended", longPressEllapsed)
          pressableElements[i].style.transform = `translateX(0px)`;

          if(ev.deltaX > 30) {
            this.handleSwipe(this.chatMessages[i]);
          }
          else if(longPressEllapsed > 500) {
this.handleLongPress()
          }
        }
      });
      gesture.enable(true);
      pressableElements[i].addEventListener('contextmenu', (evt) => {evt.preventDefault()});
    }
Malcolm Swaine
  • 1,929
  • 24
  • 14