Tap and Drag Animation Domination Part 1: Working with the DOM

Working with DOM elements in Sencha Touch 2 is a topic that has very little coverage from within the official documentation and the community at-large. Officially, you are strongly encouraged to develop apps using only the rich set of components that Sencha has provided to you in their framework. However, if you need to impress your manager by creating custom Touch 2 components or extend out-of-the-box components with custom gestures and animations, it is vital that you understand how the DOM system operates. Because nothing impresses I.T. managers more than a completely gratuitous, well-executed animation!

Working with DOM elements in Touch 2

The first thing to understand about Components is that they generate DOM elements as illustrated by the following example

Sencha Touch Generated Output
 Ext.Viewport.add({
  xtype: 'component',
  html: 'Hello World',
  itemId: 'mycomponent',
  cls: 'customstyle'
 });
<div class="customstyle" 
     id="ext-component-1">
  <div class="x-innerhtml" 
      id="ext-element-9">
     Hello World
  </div>
</div>

You can programmatically access the top level DOM element that is created by a component (typically a <div>) by referencing the component.element property as illustrated below:

var el = Ext.ComponentQuery.query("#mycomponent")[0].element;

You can also access the DOM elements generated by components by invoking the Ext.select() method, targeting any CSS style classes that are generated by the component as illustrated by the following snippet:

// get first div tag with css style class of 'customstyle'
var htmlEl = Ext.select('div.customstyle').elements[0];

// convert to Ext.dom.Element reference
var el = Ext.get(htmlEl);

Moving between Ext.dom.Element and their corresponding components

Since the DOM element typically has the same ID property as the Sencha Touch Component that generated it, you can usually get a pointer back to the Component by using the following syntax:

// get DOM element from component
var el = Ext.ComponentQuery.query("#mycomponent")[0].element;

// get Component reference from DOM component
var cmp = Ext.getCmp(el.dom.id);

Ext.dom.Element instances are wrappers for HTML DOM elements. They give you a programmatic interface that normalizes the differences between different browser implementations. Much like another wrapper, Vanilla Ice, they don’t look like much on first glance:

dom1

However, once you dig deeper, realize that you’ve actually pulled an instance of the Sencha Touch 2 Ext.dom.Element class, and discover that there are 117 additional methods that you can invoke as well as 19 events that you can listen for (including pinch, rotate, and swipe gestures), a joyous nerdgasm is sure to follow!

Attaching DOM event listeners to Component Elements

Attaching a DOM event listener, such as a taphold gesture to an element generated by a component now becomes a relatively straightforward affair. Here’s an example that echoes the high-brow conversation of my children as I drive them to school:

el.on('taphold',
      function(event, node, options,eOpts) { 
        Ext.Msg.alert("Stop touching me!",
                      "Would you stop touching me??"
        );
      }
);

You can also attach a DOM element event listener directly to a component using the component’s listeners config property as illustrated below:

Ext.Viewport.add({
 xtype: 'component',
 html: 'Hello World',
 cls: 'customstyle',
 itemId: 'mycomponent',
 listeners: {
  element: 'element',
  'taphold': function(event, node, options,eOpts) { 
     Ext.Msg.alert("Stop touching me!",
                   "Would you stop touching me??"
     );
  }
 }
});

Now, a potential problem here is that the event listener for the taphold event returns a reference to the DOM element that fired the event (the node param) instead of the component instance that generated the DOM element. (In our case, this is likely to return back the DOM element “ext-element-9”). Fortunately, if you bind the DOM event listener to the component directly, the eOpts argument contains the id of the top-level container that had the event listener attached to it, e.g. #ext-component-1. You can simply strip the # from the string and pass it to Ext.getCmp() to get a pointer back to the Component.

Ext.Viewport.add({
 xtype: 'component',
 html: 'Hello World',
 cls: 'customstyle',
 itemId: 'mycomponent',
 listeners: {
  element: 'element',
  'taphold': function(event, node, options,eOpts) { 
              Ext.Msg.alert("Stop touching me!",
                            "Would you stop touching me??"
              );
              console.log('component ref:',   
               Ext.getCmp(eOpts.info.target.substring(1))
              );
            } // end function
  } // end listeners
}); // end viewport add

Now that you know how to access DOM elements from their generating Components (and vice-versa), you can enhance components by adding new behaviors and animations. I’ll cover this in more detail in another blog post later today.

3 thoughts on “Tap and Drag Animation Domination Part 1: Working with the DOM

  1. Pingback: Tap and Drag Animation Domination Part 2: Implementing Custom Animations with Ext.Anim | Druck-I.T.

  2. Pingback: Tap and Drag Animation Domination Part 3 of 3: Implementing Drag and Drop in Sencha Touch 2 | Druck-I.T.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s