Create JavaScript custom event

I like using this EventDispatcher constructor method, which, using a dummy element, isolates the events so they will not be fired on any existing DOM element, nor the window or document.

I am using CustomEvent and not createEvent because it's the newer approach. Read more here.

I like to wrap each native method with these names:

on, off, trigger

function eventDispatcher(){
  // Create a dummy DOM element, which is a local variable 
  var dummy = document.createTextNode('')

  // Create custom wrappers with nicer names
  return {
    off(...args){ 
      dummy.removeEventListener(...args) 
      return this
    },
    on(...args){ 
      dummy.addEventListener(...args) 
      return this
    },
    trigger(eventName, data){
      if( !eventName ) return
      
      // if the event should be allowed to bubble, 
      // then "dummy" must be in the DOM
      var e = new CustomEvent(eventName, {detail:data})
      dummy.dispatchEvent(e)
      return this
    }
  }
}

////////////////////////////////////
// initialize the event dispatcher by creating an instance in an isolated way
var myEventDispatcher = eventDispatcher();

////////////////////////////////////
// listen to a "foo" event
myEventDispatcher
  .on('foo', e => console.log(e.type, e.detail) )
  .on('bar', e => console.log(e.type, e.detail) )

////////////////////////////////////
// trigger a "foo" event with some data
myEventDispatcher
  .trigger('foo', 123)
  .trigger('bar', 987);

The above eventDispatcher could be integrated into another code, for example, a Constructor: (for example some component)

function eventDispatcher(){
  var dummy = document.createTextNode('')

  return {
    off(...args){ 
      dummy.removeEventListener(...args) 
      return this
    },
    on(...args){ 
      dummy.addEventListener(...args) 
      return this
    },
    trigger(eventName, data){
      if( !eventName ) return
      var e = new CustomEvent(eventName, {detail:data})
      dummy.dispatchEvent(e)
      return this
    }
  }
}

/////////////////////////////
// Some component: 

var MyComponent = function(){
  // merge `EventDispatcher` instance into "this" instance
  Object.assign(this, eventDispatcher())
  
  // set some default value
  this.value = 1
}

MyComponent.prototype = {
  set value(v){
    this.trigger('change', v)
  }
}

var comp = new MyComponent();

// bind a listener to "comp" (which itself is an instance of "MyComponent")
comp.on('change', e => console.log("Type:", e.type,", Value:", e.detail) )

// set some value
comp.value = 3;

👉 See my related answer, which shows a more complex implementation of the above


Perhaps something like this?

function OnPrinterStateChanged(state) {
    var evt = new CustomEvent('printerstatechanged', { detail: state });

    window.dispatchEvent(evt);
}


//Listen to your custom event
window.addEventListener('printerstatechanged', function (e) {
    console.log('printer state changed', e.detail);
});

An alternative solution would be to use function composition, but then it would be hard to remove specific listeners.

function OnPrinterStateChanged(state) {}

function compose(fn1, fn2) {
    return function () {
        fn1.apply(this, arguments);
        fn2.apply(this, arguments);
    };
}

//Add a new listener
OnPrinterStateChanged = compose(OnPrinterStateChanged, function (state) {
    console.log('listener 1');
});

//Add another one
OnPrinterStateChanged = compose(OnPrinterStateChanged, function (state) {
     console.log('listener 2');
});

EDIT:

Here's how you can do it with jQuery.

function OnPrinterStateChanged(state) {
    var evt = $.Event('printerstatechanged');
    evt.state = state;

    $(window).trigger(evt);
}


//Listen to your custom event
$(window).on('printerstatechanged', function (e) {
    console.log('printer state changed', e.state);
});