1

There is no "mousehold" event, so I wrote one:

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

@Directive({ selector: '[custMousehold]' })
export class MouseholdDirective {

  @Input() duration: number = 350; // ms
  @Output() mousehold: EventEmitter<any> = new EventEmitter();
  public timeout: NodeJS.Timer;

  @HostListener('mousedown', ['$event'])
  mousedown(event: MouseEvent) {
    if (event.which !== 1) return; // left mouse button only
    this.timeout = setTimeout(() => {
      this.mousehold.emit(event);
    }, this.duration);
  }

  @HostListener('mouseup')
  mouseup() { clearTimeout(this.timeout); }

}

This is how I attach it to an element:

<span custMousehold (mousehold)="do something ...

It works great. But I also have a click event on this same element:

<span custMousehold (mousehold)="do something" (click)="do something else ...

And I want the click event to only fire if mousehold did not fire. I've been trying with preventDefault() and stopPropagation() all over the code but they don't make a difference. The click always fires.

tom
  • 2,137
  • 2
  • 27
  • 51
  • why not emit {...event,hold:true} or {...event,hold:false} according the timeout and only use a unique function? – Eliseo Sep 19 '18 at 20:55

2 Answers2

1

You can filter a click event to check if mousehold was emitted. If so, just ignore click event.

I'm providing working plunkr to show my idea. Main issue was connected to mouse up emitted before click event. I've my small changes in mouseup listener in mentioned directive.

be4code
  • 688
  • 4
  • 15
  • This is a comment not an answer. Please show working code – Patricio Vargas Sep 20 '18 at 02:23
  • @PatricioVargas there is no any "code" word in SO [Help Center](https://stackoverflow.com/help/how-to-answer) – be4code Sep 20 '18 at 05:11
  • Yeah there's not, but follow @Eliseo example, for this case this person needs workable code as an answer not just words. Sounds like you know how to do it, why don't you show him with code then? – Patricio Vargas Sep 20 '18 at 05:16
  • While reading the question, I've just assumed that @tom needs an idea. But I'll try to edit my answer and provide working code. – be4code Sep 20 '18 at 05:22
  • 1
    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - [From Review](/review/low-quality-posts/20909295) – Lal Sep 20 '18 at 07:50
  • @Lal could you be more precise in which point my answer does not provide an answer? One more time, does answer need to provide code for copy&paste? If so, please provide a link to such rule. I have shared an idea - a point from which the author can start. After suggestion, I have added an example how to implement it. I have also provide the explanation what was the cause that first implementation was not working. – be4code Sep 21 '18 at 08:13
0

I found a solution that works and is quite compact but maybe not so elegant. Someone might post a better one. What I did was extend the directive a bit so it exposes a boolean variable to the view that tells whether the event fired:

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

@Directive({ selector: '[custMousehold]', exportAs: 'custMousehold' })
export class MouseholdDirective {

  @Input() duration: number = 350; // ms
  @Output() mousehold: EventEmitter<any> = new EventEmitter();
  @Output() fired: boolean;
  public timeout: any;

  @HostListener('mousedown', ['$event'])
  mousedown(event: MouseEvent) {
    this.fired = false;
    if (event.which !== 1) return; // left mouse button only
    this.timeout = setTimeout(() => {
      this.fired = true;
      this.mousehold.emit(event);
    }, this.duration);
  }

  @HostListener('mouseup')
  mouseup() { clearTimeout(this.timeout); }

}

In the view I can access this fired variable like this:

<span custMousehold #custMousehold="custMousehold" (click)="!custMousehold.fired ? ...

More info

tom
  • 2,137
  • 2
  • 27
  • 51