Table of Contents
Introduction
Prior to version 5, Ext JS was designed exclusively for use on desktop devices with traditional mouse input. As of version 5, we’ve added support for touch input as well, which allows Ext JS to be used on a larger selection of devices, primarily tablets, but also laptops with touch-screens. The implications of this change will likely be transparent to users of the framework, but it’s helpful to understand what’s going on behind the scenes. In this article, we’ll explore how the framework handles touch events and event normalization between devices.
Gestures In Ext JS
Perhaps the most exciting addition to the event system in Ext JS 5 is “gesture” events. Because the Sencha Touch event system forms the basis for the new Ext JS 5 event system, Sencha Touch users may find that they are already familiar with many of these gestures. For the uninitiated, gestures are complex events that are synthesized from lower-level browser events, for example, “drag”, “swipe”, “longpress”, “pinch”, “rotate”, and “tap”. Ext JS 5 takes touch gestures one step further and allows them to be triggered by mouse input in addition to touch input, or both, in the case of multi-input devices.
From the browser’s perspective, there are 3 basic events (start, move and end) that fire when interacting with a page using a mouse or touch-screen. The framework monitors the sequence and timing of these three events to determine when a gesture has occurred:
Browser | Start | Move | End |
---|---|---|---|
Desktop Browsers | mousedown | mousemove | mouseup |
Mobile Webkit | touchstart | touchmove | touchend |
IE10 | MSPointerDown | MSPointerMove | MSPointerUp |
IE11 | pointerdown | pointermove | pointerup |
When the framework determines that a gesture has occurred, it dispatches a gesture event to any Elements that are listening. Listening for a gesture event is the same as listening for any DOM event, for example:
myElement.on('drag', myFunction);
The following “single-touch” gestures will work across all supported devices and browsers, regardless of the input device that is used (mouse or touch):
Gesture | Events |
---|---|
Tap | tap, tapcancel |
DoubleTap | singletap, doubletap |
LongPress | longpress |
Drag | dragstart, drag, dragend, dragcancel |
Swipe | swipe, swipestart, swipecancel |
EdgeSwipe | edgeswipestart, edgeswipe, edgeswipecancel |
The following “multi-touch” gestures will work on all supported touch-enabled browsers when running on a device that has a touch-screen.
Gesture | Events |
---|---|
Pinch | pinchstart, pinch, pinchend, pinchcancel |
Rotate | rotatestart, rotate, rotateend, rotatecancel |
The Delegated Event Model
The Ext JS 5 event system makes a subtle but significant paradigm shift by moving away from directly attached DOM listeners to a “delegated” event model. This means that for each type of event (“mousedown”, “touchstart”, etc.), a single listener is attached at the very top of the DOM hierarchy (the window object). When a DOM element fires an event, it bubbles all the way to the top before it is handled. Internally, this complicates things just a bit, because the event system has to emulate event propagation by traversing up the DOM hierarchy from the target element, and dispatching event handlers, if needed, along the way. While, at first glance, this approach may seem needlessly complex, it bestows a few important advantages:
- The delegated event model is the key to being able to recognize when a “gesture” has occurred. The event system continuously monitors the timing and sequence of certain key events to detect if one of the supported gestures has occurred. It then seamlessly dispatches the gesture event in proper sequence along with the native events from which it was synthesized.
- It greatly reduces the number of DOM listeners that are attached, thus improving memory usage, and providing a single point for removal of DOM listeners. This has the added benefit of reducing the likelihood of memory leaks in older browsers, because it simplifies cleanup at window unload time.
- It allows “top-down” (capture) propagation of events in older browsers. Because IE8 does not support addEventListener() and the “useCapture” option, DOM events that are directly attached can only ever propagate using the bottom-up bubbling model. The delegated event model provides a way around this problem, by using its own artificial propagation routine, which implements both “bubble” and “capture” propagation. Users can attach capture listeners by simply passing the “capture” option when attaching the event, and event handlers will be dispatched in a top-down order across all browsers and devices. For example:
myElement.on({ click: someFunction, capture: true });
Potential Challenges With The Delegated Model
As with any fundamental change to the framework, it’s possible there will be incompatibility with existing code. As it relates to the new event system, existing code generally falls into one of two camps:
- Application code that uses only the Ext JS event system APIs to attach event listeners i.e. Ext.Element#addListener() or Ext.Element#on() will be blissfully unaware that there was a change. The new event system is designed to be 100% backward compatible with the Ext JS 4 event system, if application code uses ONLY the Ext JS APIs to attach listeners.
- Application code that mixes and matches Ext JS with other JavaScript libraries, or code that uses DOM APIs to directly attach events to elements may be negatively impacted by the switch to the delegated event system. This occurs because the timing of directly attached event handlers is now different relative to the timing of their delegated counterparts. This may cause issues if application code expects event handlers to run in a specific order, however, it will likely be most obvious when event handlers attempt to stop propagation of a given event. There are two rules to remember here:
- Delegated listeners can call stopPropagation(), and it will stop the delegated event system’s emulated propagation; however, it will not prevent any directly attached listeners from firing. The reason is that, by the time delegated listeners are processed, it is too late to prevent any directly attached listeners from firing because the native event has already bubbled to the top of the DOM.
- If a directly attached DOM listener calls stopPropagation(), it will prevent ALL delegated listeners from firing, including those on elements below it in the DOM. This is because stopPropagation() on a directly attached event will prevent the native event from bubbling to the top, thereby preventing it from being handled by the delegated event system. This also has the potential of disabling gesture recognition, because gestures are handled at the top of the DOM.
If for some reason, the delegated model is undesired, listeners can opt out using a simple flag in the options object:
myElement.on({ click: myFunction, delegated: false });
However, caution is advised when opting out of the delegated event model, because it can produce the same negative effects (as described above) as for directly attached DOM listeners, especially when stopPropagation is involved.
Event Normalization
One of the primary goals of the new event system is to enable existing Ext JS apps to run on tablets and touch-screen laptops (with little or no effort required to upgrade the app). In order to accomplish this, the framework performs some basic event normalization behind the scenes. When a listener is requested for a mouse event such as mousedown or click, the framework actually attaches a similar touch event or pointer event (if the device supports such events). For example, if the application attempts to attach a mousedown listener:
myElement.on('mousedown', someFunction);
On Mobile Safari, the event system will translate it to:
myElement.on('touchstart', someFunction);
However, when running in IE11, that same listener would be translated to:
myElement.on('pointerdown', someFunction);
This allows interaction with the touch-screen to behave mostly the same as mouse interaction.
The following mouse events are translated directly to touch or pointer events when running on a touch-enabled device:
- mousedown -> touchstart or pointerdown
- mousemove -> touchmove or pointermove
- mouseup -> touchend or pointerup
- click -> tap
- dblclick -> doubletap
For some mouse events, however, there is no suitable analog in the touch world. If an application relies on any of the following events, it is up to the developer to decide if and how the feature should be implemented when using touch input:
- mouseover
- mouseout
- mouseenter
- mouseleave
While event normalization will benefit most applications, there may be an occasional need to opt out. Ext JS 5 provides the new “translate” event option for this very purpose:
myElement.on({ mousedown: myFunction, translate: false });
Setting the “translate” option to false will prevent the event system from performing any event normalization for this listener, so the handler function will only be called if a “real” mousedown occurs.
Conclusion
Ext JS has long been the leading framework of choice for HTML5 desktop apps, but now the lines between desktop and mobile are becoming increasingly blurred. The new Ext JS 5 event system, with its gestures and event normalization, positions Ext JS to continue to excel both on the traditional desktop-style device and in the new world of touch-enabled devices and browsers.
Nice post from the Future :) (publish date – April 09, 2014) Looking forward to update our project to Extjs 5.
Very excited to get some of these functions implemented in our applications. Drag is going to be a huge benefit in our design tools!
Very interesting.
But if touch events and gestures are implemented now in ExtJS, does Sencha Touch has a future and if yes, which one?
Man! I’m almost finished writing an application in touch that’s a port from an EXT 4 application. Now you tell me! :)
@Patrick Sencha Touch is alive and well. The next release of Sencha Touch will share the event/gesture system with Ext JS 5 and as a result both frameworks will run on pretty much any desktop or mobile device (IE8+ for Ext, IE10+ for touch). The choice of whether to use Ext JS or Sencha Touch boils down to what kind of device you are primarily targeting.
Sencha Touch is optimized for mobile devices, and it’s components are designed primarily with touch interactions in mind. This makes it ideal for designing and building mobile user interfaces for smartphones and tablets. Although the next release of Sencha Touch will run on desktop devices, it currently does not have desktop-like UI components that users have come to expect on desktop devices.
Ext JS is optimized for desktop browsers, and comes with support for legacy browsers all the way back to IE8. Its UI components are designed for desktop browsers, and performance is optimized for the desktop as well. If your primary goal is to create an app for desktops and laptops (including those with touch-screens), with crossover usage on tablets, use Ext JS.
The goal of adding touch support in this version of Ext JS is to enable existing apps, and apps designed primarily for desktop use, to run on devices that have touch-screen input. For a truly optimal mobile user-experience, we still recommend Sencha Touch.
Thanx for your answer, Phil.
If we plan to produce an app primarily for mobile devices, and then to port it to desktops/laptops, shall we have facilities to port the sencha touch app to ExtJs, or should we develop a specific version on ExtJS for desktops/laptops?
Also, I read recently somewhere (can not remember where) that ExtJS and Sencha Touch should converge in the near future to a unique framework. Is it true? If yes, when should this framework be available to market?
Patrick, there are no plans to fully converge the 2 frameworks into one, but as of Ext JS 5, and with the next coming release of Sencha Touch, the two frameworks will share a common core. This means you can develop a single app that shares a common application architecture, and data layer, and write separate view layers for mobile and desktop. The key is the new “framework” property in app.json – it allows you to have one app, and generate separate builds of that app using Ext JS for your desktop UI and Sencha Touch for mobile. Further documentation on this is in the works.
Great post! Its really exciting to see gestures to be a part of ExtJS framework and having a common data package for ExtJS and Touch apps.
I have 2 suggestions…
1. Can we have guide for extjs/touch showing a full-blown TDD approach? I understand there is a unit testing documentation available under ExtJS however having an end-to-end example will really add value?
2. Are there any plans to have a default Android environment packaged with Sencha Architect? Today there is a need to setup the entire Android environment separately before I start building native apps.
Phil, thanx again for clarifying this point.
When will the new Sencha Touch version be available?
Should we begin to develop our app on the current version?
If yes, will it be simple to migrate to the new Sencha Touch version and benefit from the unified core with ExtJS 5 to generate the desktop/laptop version then?
@Peter, We announced the tablet support in SenchaCon 2013 and the sessions and news have since been publicized a while back. Any possibility we will see you at SenchaCon 2014 in November? https://staging.sencha.com/blog/senchacon-2014-is-coming-to-the-san-francisco-bay-area/
Hi, the Japanese translation of this blog article is here: http://www.xenophy.com/sencha-blog/10880
Link to the Japan Sencha User Group: http://www.meetup.com/Japan-Sencha-User-Group/
will it be simple to migrate to the new Sencha Touch version and benefit from the unified core with ExtJS 5 to generate the desktop/laptop version then?
http://www.obataborsi.tv/2013/12/info-obat-aborsi.html#.UzIMhanGWIU