How to trigger JavaScript custom events correctly

6.6k views Asked by At

I am struggling to understand how a custom event type is linked to a specific user action/trigger. All documentation seems to dispatch the event without any user interaction.

In the following example I want the event to be dispatched once a user has been hovering on the element for 3 seconds.

var img = document.createElement('img');img.src = 'http://placehold.it/100x100';
document.body.appendChild(img)
var event = new CustomEvent("hoveredforthreeseconds");

img.addEventListener('hoveredforthreeseconds', function(e) { console.log(e.type)}, true);


var thetrigger = function (element, event) {
    var timeout = null;
    element.addEventListener('mouseover',function() {
        timeout = setTimeout(element.dispatchEvent(event), 3000);
    },true);
    element.addEventListener('mouseout', function() {
        clearTimeout(timeout);
    },true);
};

I have a trigger but no logical way of connecting it to the event.

I was thinking about creating an object called CustomEventTrigger which is essentially CustomEvent but has a third parameter for the trigger and also creating a method called addCustomEventListener, which works the same as addEventListener but when initialised it then passes the target Element to the custom event trigger which then dispatches the event when it's instructed to.

2

There are 2 answers

0
TarranJones On

I have created a method called addCustomEventListener, which works the same as addEventListener but when initialised passes the target Element to the custom event trigger which dispatches the event when it says, so in this case it only dispatches if the timeout reaches 3 seconds.

var img = document.getElementById('img');

window.mouseover3000 = new CustomEvent('mouseover3000', {
  detail: {
    trigger: function(element, type) {
      timeout = null;
      element.addEventListener('mouseover', function() {
        timeout = setTimeout(function() {
          element.dispatchEvent(window[type])
        }, 3000);
      }, false);
      element.addEventListener('mouseout', function() {
        clearTimeout(timeout);
      }, false)
    }
  }
});

window.tripleclick = new CustomEvent('tripleclick', {
  detail: {
    trigger: function(element, type) {
      element.addEventListener('click', function(e) {
        if(e.detail ===3){
          element.dispatchEvent(window[type])
        }    
      }, false);
    }
  }
});
EventTarget.prototype.addCustomEventListener = function(type, listener, useCapture, wantsUntrusted) {

  this.addEventListener(type, listener, useCapture, wantsUntrusted);
  window[type].detail.trigger(this, type);
}

var eventTypeImage = function(e) {
  this.src = "http://placehold.it/200x200?text=" + e.type;
}

img.addEventListener('mouseout', eventTypeImage, false);
img.addEventListener('mouseover', eventTypeImage, false);
img.addCustomEventListener('mouseover3000', eventTypeImage, false);
img.addCustomEventListener('tripleclick', eventTypeImage, false);
<img id="img" src="http://placehold.it/200x200?text=No+hover" ;/>

I think this could be useful to others so please feel free to improve on this.

1
teacup On

Custom events have to be triggered programatically through dispatchEvent, they are not fired by the DOM. You will always need to explictly call them in your code, such as in response to a user-generated event such as onmouseover, or a change of state such as onload.

You're very close to a working implementation, however you're immediately invoking dispatchEvent in your setTimeout. If you save it into a closure (as below) you can invoke dispatchEvent while passing your element after setTimeout has finished the timeout.

It's also good practice to declare your variables at the top of a file, to avoid possible scope issues.

var img = document.createElement('img'), timeout, event, thetrigger;

img.src = 'http://placehold.it/100x100';
document.body.appendChild(img);

img.addEventListener("hoveredForThreeSeconds", afterHover, false);

thetrigger = function (element, event) {
    timeout = null;
    element.addEventListener('mouseover',function() {
      timeout = setTimeout(function(){ element.dispatchEvent(event) }, 3000);
    },true);
    element.addEventListener('mouseout', function() {
        clearTimeout(timeout);
    },true);
};

function afterHover(e) {
    console.log("Event is called: " + e.type);
}

event = new CustomEvent("hoveredForThreeSeconds");

thetrigger(img, event);