Example App

Download the example

First of all, go ahead and download the example we'll be using in this guide. No need to peek at it just yet, we'll be going through the whole thing anyway.

Download the .zip

A look at app.js

The functional aspect of all apps are contained in a file named app.js (we'll talk about the rest of the .zip content later). We'll be using this example throughout this guide.

It might look confusing at first, but rest assured we'll be explaining each section in some detail.

(function() {

  return {

    // Here we define AJAX calls
    requests: {

      fetchBookmarks: function() {
        // An event will trigger when this request happens (L#40)
        return {
          url: '/api/v1/bookmarks.json',
          type: 'GET'
        };
      },

      addBookmark: function() {
        return {
          url: '/api/v1/bookmarks.json',
          type: 'POST',
          data: {
            ticket_id: this.ticket().id()
          }
        };
      }
    },

    // Here we define events such as a user clicking on something
    events: {

      // The app is active, so call requestBookmarks (L#65)
      'app.activated': 'requestBookmarks',

      'fetchBookmarks.always': function(data) {
        this.renderBookmarks((data || {}).bookmarks);
      },

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

      'addBookmark.always': function(data) {
        this.ajax('fetchBookmarks');
      },

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

      'addBookmark.fail': function() {
        services.notify(this.I18n.t('add.failed', { id: this.ticket().id() }), 'error');
      }

    },

    // Below this point, you're free to define your own functions used by the app

    requestBookmarks: function() {
      // Make a request called fetchBookmarks (L#15)
      this.ajax('fetchBookmarks');
    },

    renderBookmarks: function(bookmarks) {
      this.bookmarks = bookmarks;
      this.switchTo('list', {
        bookmarks:            this.bookmarks,
        ticketIsBookmarkable: this.ticketIsBookmarkable()
      });
    },

    ticketIsBookmarkable: function() {
      var status = this.ticket().status() || 'closed';
      if ( status == 'closed' ) { return false; }

      var ticketID = this.ticket().id(),
          alreadyBookmarked = _.any(this.bookmarks, function(b) {
            return b.ticket.nice_id === ticketID;
          });

      return !alreadyBookmarked;
    }

  };

}());

This is an app to manage bookmarked tickets in Zendesk. You can see your bookmarks, add a bookmark for the ticket you are looking at, and remove bookmarks.

A note on the structure

The source is written as a Javascript function expression that is invoked at once. The app is completely defined by a Javascript object returned by this function.

Eliminating the contents of the app, the structure looks like this:

(function() {

  return {
    //app goes here
  };

}());

This Javascript object can contain any property you need: internal data, functions and so on. Some properties, like events and requests, are meaningful to the framework. These are the basis of how apps work in Zendesk, and we will be looking at them in detail later on in this guide.

Important: In some cases writing functions outside of the return block can cause memory leaks. If your app is found to cause memory leaks within Zendesk it will be rejected during our approval process. To learn more about memory leak patterns in JavaScript please see this article.

User Interface

You're probably wondering where the interface for our example app is defined. Apps use Handlebar.js templates (more on those later) to define your app interface.

Here is a look at a template for this app:

<div>
  <ul>
    {{#bookmarks}}
      <li data-bookmark-id="{{id}}">
        <a href="#/tickets/{{ticket.nice_id}}">{{ticket.subject}}</a>
      </li>
    {{/bookmarks}}
  </ul>

  {{#unless bookmarks.length}}
    <p>{{t "none"}}}</p>
  {{/unless}}

  {{#if ticketIsBookmarkable}}
    <button class="btn btn-inverse bookmark">{{t "bookmark_this_ticket"}}</button>
  {{/if}}
</div>

How it looks in Zendesk

This particular app is going to be placed on the side of the ticket interface inside Zendesk. It will look like this (it's on the right!):

Next Step: Events →