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.
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.
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.
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>
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!):