Introducing React ReExt – Sencha Ext JS Components in React! LEARN MORE

Delegated Events and Gestures in Ext JS 5

April 9, 2014 121 Views
Show

Introduction

Gestures in Ext JS 5Prior 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:

  1. 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.
  2. 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.
  3. 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:

  1. 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.
  2. 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:
    1. 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.
    2. 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.

Show
Start building with Ext JS today

Build 10x web apps faster with 140+ pre-build components and tools.

Latest Content
Discover the Top 07 Architecture Patterns used in Modern Enterprise Software Development

Developing software without an architecture pattern may have been an option back then. However, that’s…

JavaScript Design Patterns: A Hands-On Guide with Real-world Examples

As a web developer, you know how popular JavaScript is in the web app development…

Virtual JS Days 2024のハイライト

2024年2月20日~22日、第3回目となる「Virtual JavaScript Days」が開催されました。JavaScript の幅広いトピックを採り上げた数多くのセッションを実施。その内容は、Senchaの最新製品、ReExt、Rapid Ext JSまで多岐にわたり、JavaScriptの最新のサンプルも含まれます。 このカンファレンスでは多くのトピックをカバーしています。Senchaでセールスエンジニアを務めるMarc Gusmano氏は、注目すべきセッションを主催しました。Marc は Sencha の最新製品「ReExt」について、詳細なプレゼンテーションを実施。その機能とメリットを、参加者に理解してもらうべく詳細に説明しました。 カンファレンスは、Senchaのジェネラルマネージャを務めるStephen Strake氏によるキーノートでスタートしました。キーノートでは、会社の将来のビジョンについての洞察を共有しています。世界中から JavaScript 開発者、エンジニア、愛好家が集まるとてもエキサイティングなイベントとなりました。これは、JavaScript…

See More