Events

Almost all activity in your app will happen in event handlers - responding to user events, AJAX responses and framework events. See Getting Started: Events for a look at how to specify events.

Describing and Handling

Each event you specify in your events hash takes the following shape:

'[event name] [optional event target]': [event handler]

The event name describes the kind of event, and the event target is an optional string that describes a target for this particular event. For DOM events, the target takes the shape of a CSS selector.

Some examples follow.

With no target:

 'app.activated': function() {
   //handler code
  }

With a target that is a CSS selector:

 'click .save': function() {
   //handler code
  }

With a named function as a handler:

 'click .save': 'saveStuff'

Handler invocation

The event handler is invoked with an object that holds event data as the first argument. The contents of this object depends on the kind of event. Handlers are also invoked in the context of your app. I.e inside your handler, the value of this will be the app.

Example:

  'app.activated': function(data) {
    if(data.firstLoad) {
      this.showWelcomeMessage();
    }
  }

// .. later in your app

showWelcomeMessage: function() {
  alert("Welcome!");
}

When the above event handler is invoked by the framework, it is passed some data. Specifically for the app.activated event, the handler is passed a Javascript object that has a firstLoad property if your app was just activated for the first time. Also note that within the handler you have access to other functions in your app, via the this variable.

The event handler may be passed additional arguments, depending on the event. For example, the event fired when an AJAX call completes will invoke the handler with the response data as a second argument.

Kinds of Events

The framework supports a few kinds of events, which are described below. Some of them are available to all apps, and some are available based on the location of your app. We will call out the per-location events specifically in the documentation.

Global Events

The following four kinds of events are global, available to all apps:

Per-location Events

In addition to global events, your app can use some events that depend on the location that your app runs in.

These events typically have to do with changes to Zendesk data that is relevant to that location. For instance, if your app runs in the ticket sidebar in a Zendesk ticket tab, you will have access to a number of events that are fired when various fields on the ticket are changed by the user. These events will allow you to react to changes in Zendesk data.

Framework Events

These types of events fire when something external happens to the app. Generally these are "lifecycle" type events.

app.activated

Fired when the app becomes active on the page.

events: {
  'app.activated': function(data) {
    this.doSomeFunction();
  },
  ...
}

Note: When this event fires the very first time for your app, the event data object passed to your handler will include a special firstLoad property.

Note: It is possible that data that comes from Zendesk servers (e.g. ticket or user data) will not yet be fetched by the time app.activated is fired. If your app cannot run without certain data, you may want to use data events (see below) to transition away from the initial state only when all the data is ready. For example, if you cannot proceed without ticket status and requester ID, you might use the following guard:

events: {
  'app.activated':               'onActivated',
  'ticket.status.changed':       'loadIfDataReady',
  'ticket.requester.id.changed': 'loadIfDataReady'
},

onActivated: function() {
  this.doneLoading = false;
  this.loadIfDataReady();
},

loadIfDataReady: function() {
  if ( !this.doneLoading && this.ticket().status() != null && this.ticket().requester().id()) {
    this.doneLoading = true;
    this.switchTo('someOtherState');
  }
}

app.deactivated

Fired when the app becomes inactive. This can mean different things depending on the location of your app. If your app is on a ticket sidebar, it means that the user switched away from the tab containing this instance of your app.

DOM Events

When a user does something, like clicking or typing inside your app, you may want to perform actions based on that event. DOM events are perfect for this.

These events are specified with the name of the DOM event and a CSS selector for the DOM elements on which you'd like to track that event.

events: {
  'click .bookmark': function(event) {
    event.preventDefault();
    this.ajax('addBookmark');
  },
  ...
}

The example above is fired when user clicks on an element within your app with the specified .bookmark class. You can also specify multiple event names and/or selectors separating them by commas. You can use any event name and any selector that jQuery supports. Refer to the jQuery Event documentation for more.

Request Events

When a request is made, you can watch for the outcome as an event.

events: {
  'addBookmark.done': function() {
    services.notify(this.I18n.t('add.done', {
      id: this.ticket().id()
    }));
  },
  ...
}

The above examples says that when the addBookmark request is done successfully, display a notification to the current user.

There are a number of possible outcome events with requests:

Event Meaning
.done When the request was completed without error
.fail When the request was made but an error occured
.always When the request is made, no matter the outcome

Custom Events

The framework supports arbitrary custom events you can use to implement your app's functionality. The mechanism to fire an event is the trigger function. Here's an example:

events: {
  'foo': function(data) {
  }
}

//later in your app

this.trigger('foo', {arg: 1});

The trigger call above will cause the foo handler function to be called. This capability can be useful to structure your app's features in terms of events that get fired at various points.

Ticket Sidebar Events

In addition to the global events above, apps that run in the ticket sidebar within Zendesk ticket tabs have some additional events they can use.

Here is an example of that from the built-in Highrise app:

'ticket.requester.email.changed': function() {
   var requesterEmail = this.ticket().requester().email();
   if ( !requesterEmail ) { return; }
   this.ajax('lookupByEmail', requesterEmail, this.setting('token'));
  }

The name of the event above is ticket.requester.email.changed, and it means "fire this event whenever the requester's email address changes".

Briefly: the above code attempts to issue an AJAX request whenever the requester's email address changes.

You will notice that in the event handler above, we are retreiving the requester's email address using the following Javascript code:

var requesterEmail = this.ticket().requester().email();

This uses the framework's data API to get at the email address. You will find the full documentation for this API later on in this Reference Guide.

Here is a listing of all the events that your ticket sidebar app can listen to:

  • ticket.type.changed
  • ticket.subject.changed
  • ticket.priority.changed
  • ticket.status.changed
  • ticket.description.changed
  • ticket.tags.changed
  • ticket.requester.id.changed
  • ticket.requester.email.changed
  • ticket.requester.name.changed
  • ticket.requester.externalId.changed
  • ticket.assignee.group.id.changed
  • ticket.assignee.user.id.changed
  • ticket.assignee.user.email.changed
  • ticket.assignee.user.name.changed
  • ticket.assignee.user.externalId.changed
  • ticket.collaborators.changed
  • ticket.sharedWith.changed
  • ticket.custom_field_<custom field ID>.changed

These events are fired when the respective properties on the ticket change, due to user interaction or when Zendesk first loads the ticket, or even when other apps make changes to the ticket.

Of special note is the ticket.custom_field_<custom field ID>.changed event. This event can be used to listen for changes to custom ticket fields. In the App code, this will end up looking like the following:

events: {
  "ticket.custom_field_1234": "customFieldChanged"
}

In the above example, 1234 is the ID of the custom field you are interested in listening for changes to.

All these events have corresponding Data API methods you can use to actually inspect the data.

Dynamic events

In addition to subscribing for the specific .changed events for the Ticket Sidebar, it is also possible to subscribe for a wildcard event that will fire for any of the above events.

The exact syntax that should be used for the wildcard event is:

events: {
  "*.changed": function() {
  }
}

As with other events, the first parameter to any event handler will be a data object. In the case of the wildcard event there will be two special properties available on the data object to help describe which event triggered the wildcard. The two special properties are:

Property Meaning
propertyName This will be the underlying property that triggered the wildcard event
newValue This will be the value of the underlying property after the change

The example below illustrates their use:

events: {
  "*.changed": function(data) {
    var propertyName = data.propertyName; // "ticket.assignee.user.email"
    var newValue = data.newValue; // "sally.agent.1@example.org"
  }
}

Dynamic events can be useful in identifying and handling events that occur to fields that might be configured by the admin who installed the app. The most likely scenario for this would be a custom field where an ID was set as a setting for an app installation. The example below illustrates such a scenario:

/*
Assumes the admin who installed the app has provided "3245" as an ID to an
app parameter named "some_custom_field_id" when installing
*/

events: {
  "*.changed": "handleDynamicEvents"
},

handleDynamicEvents: function(data) {
  var propertyName = data.propertyName, // "custom_field_3245"
      customFieldID = this.setting('some_custom_field_id'); // "3245"
  if (propertyName === 'ticket.custom_field_'.fmt(customFieldID)) {
    // Do something related to that custom field...
  }
}