• log out

How events work

On the client, Events in Qbix are instances of Q.Event, which is used quite a bit. They support the following methods:

  • event.handle(args...) executes the handlers in order, and sets event.occurred to true. You can also do event.handle.apply(subj, args...)
  • event.set(handler, key) adds a handler to the event
  • event.add(handler, key) adds a handler and also executes it right away if event.occurred is true
  • event.remove(key) removes the handler, if any
  • event.removeAllHandlers() does what it says

Handlers can be anything that one can pass to Q.handle(), including functions, strings, or other Q.Event objects.

The new Q.Event(callback, key) constructor can be used as a convenient way to set an initial callback for the event:

First.onSomeEvent = new Event(callback, 'First');

Event factories

There are times you want to create Q.Event objects on demand, for example when someone wants to add a handler or trigger one event out of a space of many possible events. You can create event factories with the following:

var defaults = ["", ""];
First.onConnect = Q.Events.factory(
  null,
  defaults, // used in place of missing fields
  callback // when a new event is created
);
First.onConnect("something").set(handler, key);

// ... somewhere else:
	
First.onConnect("something").handle(arg1, arg2);

In the example above, the factory is called with arguments ("something", "") — the default is used for the second argument. Under _internal["something"][""] it creates a new Q.Event if it doesn't already exist there. The (optional) callback is called whenever a new event is added.

Examples

By convention, names of events begin with onSomething if the event is fired after Something, beforeSomething if the event is fired before it.

For example here are some events fired by the Q.js library itself:

  • Q.onInit when Qbix initializes,
  • Q.onDOM when the DOM is ready,
  • Q.onReady the first time everything has been activated,
  • Q.onJQuery if jQuery has been loaded,
  • Q.onLoad for the window's load event,
  • Q.onUnload for the window's unload.event,
  • Q.onOnline for the window's online event,
  • Q.onOffline for the window's offline event,
  • Q.onHashChange for the window's hashchange event,
  • Q.onPopState the window's popstate event,
  • Q.beforeActivate before things are activated,
  • Q.onActivate after things are activated,
  • Q.loadUrl.options.onLoadStart occurs when page requests are initiated,
  • Q.loadUrl.options.onLoadEnd occurs after page requests are fully completed,
  • Q.loadUrl.options.onActivate occurs after a dynamically loaded page has been activated,
  • tool.Q.beforeRemove occurs before a tool is removed
  • Q.Page.onTool(id) occurs after a tool is constructed on a page

Qbix also makes extensive use of events on the PHP side as well.

Extending events

Here is how Q.extend works with events:

function handler() { };
function override() { };
var defaults = {
  foo: "bar",
  onStuff: new Q.Event(handler, "baz");
};
var result = Q.extend({}, defaults, {
  onStuff: {baz: override}
});

The above code does something along the lines of result.onStuff.set(handler, "baz"), overriding the previous callback. In short, if you merge an plain object over a Q.Event, it results in a bunch of calls to event.set(override, key), and if you merge a Q.Event over an already Q.Event, it is simply added to the list of other event handlers for that event.

This comes up when you want specify event handlers as part of providing options to a function.

Events also have onSet(), onRemove(), onFirst() and onEmpty() for those rare times you need to know when the first handler is attached, the last handler is removed, etc. This is useful for example for opening and closing pooled connections.

Additional methods

You can also use various methods to declaratively create special events based on existing ones, in the style of reactive programming:

var newEvent = Q.Event.from(window, 'mousemove')
  .until(someOtherEvent)
  .then()
    .map(transform)
    .filter(test)
    .debounce(milliseconds)
    .throttle(milliseconds);
var key = newEvent.add(handler);