The Fundamentals - Sencha Touch Essentials - Hands-On Sencha Touch 2 (2014)

Hands-On Sencha Touch 2 (2014)

Part I. Sencha Touch Essentials

Chapter 3. The Fundamentals

Before we create a real-life Sencha Touch application, let’s focus on the fundamentals. This chapter will cover all the Sencha Touch basics: how to create a component, how to reference it (creating a selector), and how to listen to their events.

All of the Sencha Touch visual components (like panels, lists, and toolbars) extend from the Ext.Component class. This base class gives every component the ability to set certain standard layout-related properties, such as height, width, margin, padding, and style, or set content with the html or template (tpl) configs. Every component in Sencha Touch can be rendered to the DOM.

In this chapter, you’ll learn:

§ How to instantiate a basic component

§ How to implement templates

§ How to make references to components

§ How component traversing works

§ How to make references to DOM nodes

§ How to fire and remove events using event handling

NOTE

You can test the examples in this chapter from my GitHub repo or you can open a Sencha Fiddle and try it out yourself. (When using the Sencha Fiddle, make sure you choose the Sencha 2.3.x framework.)

Instantiating a Basic Component

The first technique we’ll discuss is how to instantiate and configure a basic component. In Sencha Touch 2 (and in Ext JS 4), this works a little different than how you do it with native JavaScript code.

In native JavaScript, you use the new operator to create a new object instance:

var helloworld = new Object();

helloworld.html = "Hello World!";

JavaScript is a prototype-based language that contains no class system, as opposed to OOP-based languages such as C++ or Java. Because there is no class system in JavaScript, you could write JavaScript the object-oriented way, by creating a function. Let’s assume I defined a new class called Component and I want to create an instance c from it:

//function Component(html) { this.html = html }

var c = new Component('Hello World!');

Let’s do the same with Sencha code. You can create an instance of a Sencha Touch view component (a defined Sencha Touch framework class) as follows:

var c = Ext.create('Ext.Component', {

//key value pairs here, i.e.

html: 'Hello World!'

});

As you can see, in Sencha Touch you use a method, Ext.create(), to create a new object instance (in this case, Ext.component). This is because Sencha Touch has a built-in class system and class loader.

In this example, I create an Ext.Component and I pass in a configuration object with class properties (html:"Hello World!"). It is just a plain object with key/value pairs. (Yes, it looks like JSON, although in JSON you need to specify the key/value pairs as strings.)

NOTE

What about the new operator? In native JavaScript, you would use the new operator to instantiate objects—for example: var obj = new Object(). While developing with Sencha Touch, you will rarely use the new operator (although you could). The reason is because the new operator won’t inform the Sencha loader to load the required classes in the background (which would cause runtime errors), and thus you would need to take care of any dependencies yourself.

A much simpler way to render components to the DOM is what we call object literal notation (or lazy instantiation). You will probably use this more often when building real-world applications:

var c = {

xtype: 'component',

html : 'Hello World'

}

Wait a minute! What is an xtype? An xtype is an alias that stands for the following key/value pair: alias: widget.<some-component>. You would normally use an xtype in these two situations:

§ When you define your own custom class (a blueprint for objects you create), you set an alias name to this component so you can easily refer to it later.

§ To create a component instance in the object literal notation, use the xtype defined in the class blueprint (as above).

NOTE

In the next chapter, I will discuss how to create your own custom class.

Every Sencha view component has an xtype name, which can be found in the API docs. Usually, the name of the xtype is the class name without Ext, dots, or capital letters, such as Ext.List versus xtype:'list', or Ext.navigation.View versus xtype:'navigationview'.

TIP

When you use Sencha Architect for building Sencha Touch or Ext JS apps and you are creating an interface, xtype has a different name. You will need to look for the setting useralias. In the code that it generates, Sencha Architect will use alias: widget.<useralias-name>. So, in other words, xtype: <useralias-name> is equivalent to alias: widget.<useralias-name>.

When you instantiate components (and you are not using the sencha-touch-all.js/sencha-touch-all-debug.js frameworks), you will need to tell the Sencha Ext.Loader to load the corresponding Sencha class into memory. The Ext.Loader is a mechanism that loads all the correct classes and dependencies for you in the right order. (If you are familiar with Java, you can compare it to the import lines at the top of your class.) When you define your own classes and you are nesting xtypes, you can tell the Ext.Loader to load the required Sencha classes by putting them into therequires array. When instantiating components with Ext.create(), you can load these classes by adding them to the Ext.require() method; for example, Ext.require("Ext.List"); or requires: ["Ext.List"],. When would you use the Ext.create() method? It is generally used for testing purposes or prototyping.

Configuration objects can be nested within each other. This is a declarative approach, which lets you describe the object as you create it. Of course, you can’t remember every config setting from each component, which is why it’s important to always have the API docs with you.

NOTE

When you are prototyping these examples with the Sencha Fiddle, or when you are using my GitHub examples, you will notice that I do not use Ext.require(Ext.Component). This is because in this example I make use of the -all.js version of the framework, which includes all Sencha classes and therefore has no dynamic loading.

Let’s look at another example. This is a runnable example you can test yourself. Here I use Ext.create() to create a simple red box and render it to the DOM:

Ext.onReady(function() {

Ext.create('Ext.Component', {

html: 'Hello World!',

style : { background: 'red' },

cls: 'box',

width: 300,

height: 100,

renderTo: Ext.getBody()

});

});

TIP

In this example, the component will be created when the DOM is ready after loading and executing the Sencha Framework; see Ext.onReady(). (You can compare Ext.onReady with $(document).ready in JQuery, but note this is not the same as window.onload() in JavaScript, which will be fired after the DOM is ready and all images and resources are loaded.)

Ext.create() creates the component instance and, with the renderTo property, places the component (which is technically a set of HTML <div> tags) into the body of the HTML page; see Ext.getBody().

As we saw in the example earlier, these components have a hardcoded html property. That’s helpful for prototyping as well, but you will probably not use it often in production apps. In that case, you want to push dynamic content into the component before rendering or while running. We’ll discuss this next.

Implementing Templates

In the previous examples, I hardcoded data in the view components. Obviously that is not ideal. You will probably want to make it dynamic. We will use templates for this. In Sencha Touch, templates are little predefined HTML snippets with placeholders. You can dynamically inject these HTML snippets with data.

To define such a template, you will use the Ext.XTemplate class:

Ext.create('Ext.Component', {

tpl: Ext.create('Ext.XTemplate','<h1>{name}</h1><p>{description}</p>'),

data: {

name: 'Template',

description: 'This is an example of how to configure a basic template.'

}

});

As you can see, Ext.Component enables you to assign an Ext.XTemplate. This is very nice because it allows you to inject dynamic content.

Let’s check out some runnable examples. You will define a template and inject it with data. First, you need to declare a custom object, data, which has the keys name and description. When the DOM is ready, the data will be loaded into the template:

Ext.onReady(function() {

var data = {

name: 'Taxi Amsterdam',

description: 'The only taxi in Amsterdam that does not circle around'

};

Ext.create('Ext.Component', {

tpl: '<h1>{name}</h1><p>{description}</p>',

data: data,

styleHtmlContent: true,

cls: 'box',

renderTo: Ext.getBody()

});

});

Changing the Data at Runtime

Now let’s take a look at an example that uses the setData() method to change the data at runtime:

var data = {

name: 'Taxi Amsterdam',

description: 'The only taxi in Amsterdam that does not circle around.'

};

var c = null;

Ext.require('Ext.Component');

Ext.onReady(function() {

c = Ext.create('Ext.Component', {

tpl: '<h1>{name}</h1><p>{description}</p>',

data: data,

styleHtmlContent: true,

cls: 'box',

renderTo: Ext.getBody()

});

data.description = "We like tourists a lot!";

c.setData(data);

});

In the previous code, you can see that the template (tpl) renders the data with the description “The only taxi in Amsterdam that does not circle around.” in the DOM, but at runtime this text will be immediately changed to “We like tourists a lot!” because of the setData() method.

In this example, I used two global variables: an object named c and an object named data. I did this so that I can edit the data object from elsewhere in my code. For example, if I open my debugger console and change the data.name to Tourists Taxi (data.name = "Tourists Taxi"), followed by the setData() method c.setData(data), I would modify the header title to “Tourists Taxi.”

Organizing Template Snippets

I can imagine that you don’t want to save all these HTML snippets into your JavaScript view code. Instead, you can use template snippets (Ext.XTemplate) and save those in different files. Such a template can be assigned to the tpl property:

Ext.require('Ext.Component');

Ext.onReady(function() {

var data = {

name: 'Taxi Amsterdam',

description: 'The only taxi in Amsterdam that does not circle around.'

};

var myTpl = Ext.create(

'Ext.XTemplate','<h1>{name}</h1><p>{description}</p>');

Ext.create('Ext.Component', {

tpl: myTpl,

data: data,

styleHtmlContent: true,

cls: 'box',

renderTo: Ext.getBody()

});

});

The myTpl variable contains the Ext.XTemplate snippet. It’s just a variable, so I could move it over to any other file to get (global) access to it. Notice the new Ext.XTemplate() class. Here a template is assigned to the variable myTpl, which will be configured in the component tplconfig.

In real-world applications you could decide to save all HTML templates in a custom separate (singleton) class, instead of saving it globally (Example 3-1). (See the examples in Defining Singletons and Static Members.)

Example 3-1. utils/Template.js

Ext.define('Utils.utils.Template', {

statics: {

MY_TPL: Ext.create('Ext.XTemplate','<h1>{name}</h1><p>{description}</p>');

}

});

Implementing Advanced Templates

Let’s get a bit more advanced. Now you don’t want to save the data in just a random object, but rather you want to push it from a data store (such as CabStore) to the template, as shown in Example 3-2.

Example 3-2. Advanced templates

Ext.application({

requires: ['Ext.dataview.DataView', 'Ext.data.Store', 'Ext.Component'],

launch: function() {

//create a data store with id: CabStore.

Ext.create('Ext.data.Store', {

id:'CabStore',

fields: ['name', 'description'],

data : [

{ name: "Taxi Amsterdam", description: "The best taxi service" +

"of Amsterdam."},

{ name: "Cab & Co", description: "Always fast."}

]

});

var myTpl = Ext.create('Ext.XTemplate', '<tpl for=".">',

'<div class="row">',

'<h1>{name}</h1><p>{description}</p>',

'</div>',

'</tpl>'

);

Ext.create('Ext.DataView', {

itemTpl: '<h1>{name}</h1><p>{description}</p>',

store: 'CabStore',

styleHtmlContent: true,

cls: 'box',

fullscreen: true,

height: 250

});

}

});

In the previous example, I have created a new data store with the id CabStore. It contains the name and description fields with two rows of data. I have used the myTpl XTemplate like you have seen before, only this time I created <tpl for="."> looping tags, which loop through the root (.) of all the data records. This <tpl> tag sets the template markup for every row of data.

Instead of an Ext.Component, I have created a dataview instance because Ext.DataView handles multiple template rows. Because a dataview consists of one or more items, it doesn’t require a single tpl property anymore but rather an itemTpl, which sets the HTML template for every item in the dataview. Last but not least, I have set a store with a lookup to look up the CabStore id. I don’t need an array with data anymore, because the data store contains the data from now on.

What else can you do with templates? XTemplates are very powerful. You can run conditional expressions, basic math functions, built-in variables, custom member functions, and loops into templates. Check the API documentation to discover more options for XTemplates.

I discussed how to instantiate components and inject them with custom templates. When working with components, you might also want to reference them. Let’s talk about this basic technique next.

Making References to Components

When you are working with components, you might want to select them, or you might want to make a reference or selector to them. Maybe you are familiar with other JavaScript frameworks such as jQuery or MooTools, where you can make selectors to DOM elements.

Sencha Touch can also make references to DOM elements, as we’ll discus in Making References to DOM Nodes. In practice, however, you will make references to components more often than to DOM elements, because Sencha Touch uses components instead of DOM elements.

The best practice to make references to a view component is by using a ComponentQuery:

Ext.ComponentQuery.query('selector');

The ComponentQuery searches components through the Ext.ComponentManager. It will return an array with components (even when only one component is found). In the component query, you pass in a string with the xtype:

var cars = Ext.ComponentQuery.query('car');

Or to search and select for multiple components:

var carsAndCabs = Ext.ComponentQuery.query("car, cab");

TIP

An alternative way of creating references to components is by using a refs object in the controller. Don’t worry about this now; I will discuss this topic in Chapter 6.

It’s also possible to retrieve components with a component query for id or itemId, by passing in the string id name, prefixed with a #. As itemIds are not globally unique, it is a better practice to use them instead of ids.

Ext.ComponentQuery.query('#mybutton');

USING THE GET COMPONENT METHOD

In Sencha Touch version 1 or Ext JS version 3, you could use the get component method: Ext.getCmp(id). That’s an easy way of creating a reference to a component with an id. The getCmp() method is a shorthand notation for Ext.ComponentMgr.get(id); you pass in the string id of a component and it will return an Ext.Component. If the component is not found, it will return undefined. For example, the following component query makes a reference to a component that has an id of mybutton:

Ext.getCmp('mybutton');

There might be use cases for using Ext.getCmp(). However, it is bad practice to set an id in a custom component. The issue with ids is that they need to be globally unique. That means that you can’t reuse your custom components in your apps; if you do so, strange things may happen. The trick is to use component queries with xtype or itemId instead.

You can even make your component query more complex by passing in CSS-like selectors. For example, you can select components with certain attributes by using bracket notation. In this case, I select all panels that have the attribute title="Test":

Ext.ComponentQuery.query('panel[title="Test"]');

Or we can select only child elements from a component:

Ext.ComponentQuery.query('formpanel > button');

It’s also possible to walk up and down by retrieving components (traversing nested components). The next section will discuss this concept.

Traversing Components

In the previous section, you saw component queries that look like this:

Ext.ComponentQuery.query("formpanel > button");

This component query walks through the components and selects all the child elements that match the selector. (In this case, direct button items of formpanel xtypes.) We call this traversing. For example, say you have a reference to a formpanel and you want to drill down to retrieve a particular form field.

To traverse components, you can use the up() and down() methods to retrieve the first parent or first child component:

//get first parent

myComponent.up(el);

//get first child

myComponent.down(el);

Sencha has the up() and down() traversing methods. All components have an up() method. All containers have a down() method (and also an up() method, because containers extend from Ext.Component).

myComponent.up() finds the parent component. myComponent.down() finds the child component:

var form = myButton.up('formpanel');

var input = form.down('textfield[name="lastname"]');

Now that you know how to select and traverse Sencha components by using the component query, you might be curious how to select DOM elements. We’ll look into that in the next section.

WARNING

Be aware that when Ext.ComponentQuery.query("formpanel button") returns an array with components, the up() or down() method returns the first parent or child that it finds.

To illustrate, take a look at this code snippet, which runs in the browser developer console, while previewing the example on GitHub:

> Ext.ComponentQuery.query('button')

[Class, Class]

>Ext.Viewport.down('button')

Class {onInitializedListeners: Array[0],

initialConfig: Object, id: "mybutton",

getId: function, element: Class…}

Making References to DOM Nodes

Earlier we discussed how to make references to Sencha components. But how can you select DOM nodes? Sencha works with components, so you would think that you don’t need to point to DOM nodes. That’s not completely true; especially when you are creating custom components and plug-ins yourself, you might need to work with the DOM.

NOTE

Creating custom components or plug-ins in Sencha Touch is beyond the scope of this book. It’s an advanced technique that requires an understanding of the Sencha class system, DOM, and custom styling. If you are interested in custom components, take a look at the Sencha Market, where a lot of plug-in developers share their components and plug-ins for free.

Sencha provides three ways to retrieve the DOM:

§ Getting Sencha’s version of a DOM element.

§ Getting a collection of multiple direct DOM elements.

§ Getting the direct DOM node.

NOTE

When you are working with the Sencha Fiddle, you can select the resources button to edit the index.html page.

Let’s create an HTML snippet that contains the following:

<h2 id="title">Taxi Amsterdam</h2>

<div id="description">

<p>Taxi description</p>

<p>Taxi description2</p>

</div>

Next we’ll cover a couple of techniques for retrieving DOM elements.

Ext.get()

Ext.get(el) is the trick you use to retrieve the Ext.dom.Element, which is a kind of wrapper that encapsulates a DOM element, adding simple DOM manipulation facilities and normalizing for browser differences.

You can pass in the following:

§ An ID to the node

§ A DOM node

§ An existing Ext.Element

See the following example from my browser developer console while previewing the essentials/refs-domelements/ example from my GitHub repo (or by using the Sencha Fiddle):

Ext.onReady(function() {

var title = Ext.get('title');

console.log(title);

});

This returns the Ext.dom.Element:

Class {dom: h2#title, id: "title", self: function,

superclass: Object, defaultConfig: emptyFn}

NOTE

Ext.get() is the shorthand notation for Ext.dom.Element.get().

Ext.select()

Now, let’s see how to select multiple DOM elements. For this, we can use Ext.select(selector).

You can pass in a CSS-like selector (with an xtype, itemId, or CSS class), and it returns an Ext.dom.CompositeElementLite, which is a collection of DOM elements providing methods to filter members or to perform actions upon the whole set.

Let’s reuse the code we used for the Ext.get() example, but use Ext.select() instead. Here, Ext.select("p") selects all paragraph DOM elements and returns it as a composite:

> var pars = Ext.select("p");

Class {elements: Array[2], el: Class, self: function,

superclass: Object, defaultConfig: emptyFn}

Once we have the composite, we can select the first DOM node:

> var firstPar = Ext.select("p").elements[0];

<p>Number one taxi in Amsterdam.</p>

NOTE

In vanilla JavaScript, you would use the following line of code to retrieve an array of DOM nodes by a tag name:

var pars = document.getElementsByTagName('p');

Ext.getDom()

Finally, you can also request the true DOM with Ext JS by using Ext.getDom(el).

You can pass in the following:

§ An ID to the node

§ A DOM node

§ An existing Ext.Element

Let’s reuse the code we used before, but now we’ll use Ext.getDom() instead. Here, Ext.getDom("title") returns the DOM element:

> var title = Ext.getDom('title');

<h2 id="title">Taxi Amsterdam</h2>

NOTE

In vanilla JavaScript, you would use the following line of code to retrieve a DOM node by an id:

var title = document.getElementById('title');

The previous examples showed you how to retrieve the Ext.dom.Element (Sencha’s version of a DOM element with extras), the Ext.dom.CompositeElementLite (a collection of DOM elements that you can filter), and the DOM node as it’s generated in the DOM tree.

Now that you know all the possible ways of retrieving DOM elements and Sencha components, let’s see how you can actually do something with these references (hint: we’ll need to listen to events).

Handling Events

Event handling is done via the Ext.util.Observable mixin. A mixin is a technique to support (multiple) inheritance. See Chapter 4 to read more about mixins. By adding (mixing) the Ext.util.Observable class to another Ext JS class, you are able to fire events. Under the hood, observable objects basically have a map that associates them to an event name. The Ext.Component class uses the Ext.util.Observable mixin, which means that all components are able to respond to events, because Ext.Component is the base class for every view component in Sencha Touch.

There are three types of events:

System events

Events invoked by the framework—for example, loading data with the load event.

Lifecycle events

Events invoked by the framework lifecycle—for example, painting a view with the painted event.

User events

Events invoked by the user—for example, a tap event.

This section will focus on user events, although the code for system events or lifecycle events is almost the same.

User events are events that occur when the user interacts with the mobile app. Examples include a click event (mousedown) or tap event (touchstart and touchend).

Touch events are a bit like mouse events, but there are some very important differences:

§ Clicking on a button with a mouse is much more accurate than a finger tap. The mouse arrow is precise compared to the size of your fingertips on the tap surface area. This is the reason for the design guideline that buttons and links on touch components should have a size of at least 44×44 points.

§ There is no mouseover or hover equivalent.

§ A touch is very hard to keep steady, whereas a mouse can stay at a fixed position. When your fingertips touch the surface area, a touchstart event occurs; it can directly detect a touchmove event when you move your finger, while a mouse has a mousedown event and must move for the mousemove event to be detected.

Firing Events

When you want to listen to a tap event, in native JavaScript code, your code could look like this:

function myEventHandler(ev) {

//do something

}

element.addEventListener('touchend', myEventHandler);

In Sencha Touch, when you want to fire an event from a component, you can define an event listener that listens to a certain event, such as the tap event:

listeners : {

tap: 'myEventHandler'

}

You handle events by passing a callback function to the component you’re observing. Some people call the callback function a listener, while other people call it a handler. When it comes to Sencha Touch, you can use either term; the handler syntax is just an alternative syntax for the listener code but only for buttons. Actually, there are additional ways to listen to events. You can use the handler or listeners configs, or you can add the events later with the on() or addListener() methods on the component instances.

Let’s add some event listeners. They all listen to the tap event, but they each use a different approach.

The first approach is what we have seen so far—the listeners configuration directly into the component class:

Ext.define('BookTaxiBtn', {

extend: 'Ext.Button',

xtype: 'booktaxibtn',

config: {

text: 'Book a Taxi - listeners',

margin: 5,

listeners: {

tap: 'bookTaxiEventHandler'

},

},

bookTaxiEventHandler: function(b){

console.log('You tapped the ' + b.getText() + 'button');

}

});

The next approach uses the handler config. It invokes the callTaxiEventHandler() function on a button tap. The handler works only on the Ext.Button:

var callTaxiBtn1 = Ext.create('Ext.Button', {

text: '1: Call a Taxi - handler',

margin: 5,

handler: callTaxiEventHandler

});

The next approach is the addListener() method. It takes the event name and the function-to-execute name as arguments:

var callTaxiBtn2 = Ext.create('Ext.Button', {

margin: 5,

text: '2: Call a Taxi - addListener'

});

callTaxiBtn2.addListener('tap', callTaxiEventHandler);

Here we use the short version of the addListener() method: the on() method. It takes the event name and the function-to-execute name as arguments:

var callTaxiBtn3 = Ext.create('Ext.Button', {

margin: 5,

text: '3: Call a Taxi - on'

});

callTaxiBtn3.on('tap', callTaxiEventHandler);

Feel free to test the preceding buttons. You’ll just need to wrap each button in an Ext.application.launch() method:

Ext.application({

name: 'Events',

requires: ['BookTaxiBtn'],

launch: function() {

var callTaxiEventHandler = function(b) {

console.log('You tapped the ' + b.getText() + 'button');

};

var callTaxiBtn1 = Ext.create('Ext.Button', {

text: '1: Call a Taxi - handler',

margin: 5,

handler: callTaxiEventHandler

});

var callTaxiBtn2 = Ext.create('Ext.Button', {

margin: 5,

text: '2: Call a Taxi - addListener'

});

callTaxiBtn2.addListener('tap', callTaxiEventHandler);

var callTaxiBtn3 = Ext.create('Ext.Button', {

margin: 5,

text: '3: Call a Taxi - on'

});

callTaxiBtn3.on('tap', callTaxiEventHandler);

//Display the buttons, for testing purposes

Ext.create('Ext.Container', {

fullscreen: true,

padding: 10,

items: [

callTaxiBtn1,

callTaxiBtn2,

callTaxiBtn3,

{ xtype: 'booktaxibtn'}

]

});

}

});

TIP

All of the available events for each component are listed in the API docs. If you want to read more about Touch gestures in mobile web applications, check out the W3C spec.

Removing Events

Just as you can add listeners at any time, you can remove them too. You will use the removeListener() method for this. To remove a listener, you need a reference to its function. In case you want to remove event listeners, it’s a good practice to not write event-handler function bodies inline in the code. You should always assign functions to a variable; otherwise, it will be hard to reference the function to remove (from outside the function body).

In native JavaScript, your code could look like this:

element.removeEventListener('touchend',myEventHandler,false)

To remove an event listener, use the removeListener() method, pass in the event name you want to remove, and pass a reference to the event function that will be invoked when the event occurs:

button.removeListener('tap', myEventHandler);

The next example creates a callTaxi button with a tap listener that invokes callTaxiEventHandler. This function removes the tap listener from the callTaxi button because it knows the reference to it (var callTaxiEventHandler):

Ext.application({

name: 'Events',

launch: function() {

var callTaxiEventHandler = function(b) {

console.log('You tapped the ' + b.getText() + 'button');

this.removeListener('tap', callTaxiEventHandler);

console.log('From now on, you can not call again.');

};

var callTaxi = Ext.create('Ext.Button', {

text: 'Call the Taxi',

margin: 5,

listeners: {

tap: callTaxiEventHandler

}

});

//just for testing purposes

Ext.create('Ext.Container', {

fullscreen: true,

padding: 10,

items: [callTaxi]

});

}

});

After removal, it shows a log message telling you that you cannot invoke the same function again (because the listener is removed).

NOTE

Just as the on() method is a shorthand version for addListener(), there is a shorthand version for the removeListener() function un(). So, instead of:

button.removeListener('tap', myEventHandler);

you can use:

button.un('tap', myEventHandler);

Firing Custom Events

Imagine you developed a nice interface with buttons. I will talk about code structure and MVCs later, but for now let’s say you coded all the event handlers in a separate JavaScript class (e.g., the Sencha Touch controller). Then the lead designer comes in and wants to change the interface—no more buttons but instead a list with menu items. Hmm, that’s a bummer. Now you have to change your code in two places. You have to edit the interface and the separate class with the event handler (the controller).

For situations like this, Sencha has the fireEvent() method, which you can code in your view component.

The taxiview component fires a custom calltaxi event with the fireEvent() method:

listeners : {

tap: function(e){

this.up('taxiview').fireEvent('calltaxi', e);

}

}

With this method, you can fire custom event names. The idea is that you pass (fire) events to another view component. From anywhere else in your code (e.g., in the controller), you’ll listen to this custom event name and execute the logic after it is fired:

The controller listens to the custom calltaxi event:

Ext.define('TaxiController', {

extend: 'Ext.app.Controller',

config: {

control: {

'taxiview': {

calltaxi: 'onCallTaxi'

}

}

},

onCallTaxi: function() {

console.log("Call the Taxi");

}

});

You will learn how controllers can listen to events in Chapter 6.

Summary

By now you know the Sencha Touch fundamentals: configuring components, creating templates for injecting data, and making references to components. I’ve also showed you how to create references to DOM nodes, although this is a less common practice because Sencha Touch works with components instead of DOM elements. At the end of the chapter, I discussed component event handling (i.e., how to fire and remove events).

In the next chapter, we will take a deeper look into the Sencha class system, specifically how to define a class and how class inheritance works in Sencha.