Hidden Gems in Chrome Developer Tools

As a software developer building applications with web technology, I naturally spend lots of time in my browser. For many years web developers struggled to build cross-browser applications because many browsers (notably older versions of Internet Explorer) failed to offer even minimal debugging tools — but thankfully today every browser ships with helpful developer tools and supports modern standards.

I use Google Chrome as my primary browser simply because its set of developer tools offers more features than the competition. I often joke that Chrome Developer Tools has so many features that they ran out of space to show them, so I wanted to share a few hidden gems I’ve found.

A Quick History Lesson

Google Chrome was first released in 2008. At that time, web developers didn’t have many options when it came to choosing even the most basic debugging tools — Internet Explorer did not offer any developer tools (in spite of holding the majority of the worldwide browser market share), and Safari and Firefox only offered limited tooling. Firebug (an extension for Firefox) was by far the most advanced tool available, and many of us relied on it.

But after Chrome was released, this picture quickly began to change. Chrome (at that time) extended WebKit and the built-in “WebKit Inspector” to include a variety of additional tools (like Profiles) — and soon thereafter surpassed the feature set of Firebug.

Today, Google pushes a new version of Chrome every six weeks, and these updates often include changes to the Chrome Developer Tools. At that cadance, it becomes difficult to stay on top of new features or UI changes.

Hidden Gems

When I spoke about this topic at SenchaCon a few weeks ago, I skipped what I considered to be the “basic” features of Chrome Developer Tools in order to spend more time talking about the advanced and hidden features. Chrome DevTools has what seems like 10,000 individual features, and we could literally spend days talking about them — so let’s jump right into three features I have found incredibly helpful.

Layers Panel

Although most web developers conceptually understand how nesting DOM elements affects the way the browser layers CSS applied to those elements, the fact remains that the browser displays a 2D plane. However, Chrome DevTools has a hidden feature that allows us to view the DOM layering in 3D.

To access this feature, we need to complete a few steps:

  1. Go to chrome://flags and enable “Enable Developer Tools experiments.”
  2. Restart Chrome
  3. Open Chrome DevTools
  4. Click “Settings” (the gear icon in the upper right corner)
  5. Click on “Experiments” in the left menu
  6. Check the “Layers panel” option
  7. Close, then re-open Chrome DevTools
  8. Now you should see the “Layers” tab

The Layers panel can be incredibly helpful in understanding how your DOM elements are structured on the page, and therefore how CSS rules may apply to them. It’s also very helpful in building anything involving CSS 3D Transforms — as I did in my blog post Creating Custom Layouts in Ext JS.

ESC Drawer

Sencha applications are notoriously different from web apps built with other frameworks in that Sencha applications generally involve writing very little HTML. Therefore, we tend to spend the majority of our time in the Sources tab debugging JavaScript at runtime. However, it becomes inconvenient to set breakpoints on the Sources tab, then switch to the Console tab to interact with the scope variables, then switch back to Sources (and so on).

Thankfully, Chrome DevTools offers a hidden feature to open the Console on any tab — simply hit the ESC key and the “ESC drawer” magically opens from the bottom.



The ESC Drawer allows you simultaneous access to the Console, which is certainly convenient — but it also does a whole lot more! The “Emulation” and “Rendering” tabs are full of amazing features that you should explore.

Asynchronous Call Stacks

Few things in JavaScript can be as frustrating as debugging code inside of the callback of an AJAX request. Depending on how your code is written, the scope of the callback may be set to the window object — and even worse, you might hit an error and have no idea how your runtime got to that point in the first place.


In the example above, we hit a runtime error complaining that foo() is not defined. Although we can pause on the caught exception and see which line of code throws the error, the call stack does not give us a lot of helpful information. In this case, we might be able to deduce that this function call exists in the callback for a store’s load operation, but we have no way of telling what caused the store to load in the first place.

To remedy that problem, check the “Async” checkbox on the “Call Stack” divider. The next time you hit a breakpoint you’ll be given a more comprehensive call stack — one that even tells you from where an asynchronous callback was executed.


Conclusion

Google continues to innovate and create exceptional tools for building amazing web applications. With a little bit of exploration, you’ll find a treasure trove of additional debugging functionality in Chrome Developer Tools that you may not have realized existed!

Do you have a favorite feature? Share yours in the comments below.

5 Comments   Read more

Accessibility: The Keyboard is Your Friend

Introduction

Accessibility: The Keyboard is Your FriendThe term “accessibility” is very broad and can be intimidating when first encountered. Often, this encounter comes from new business requirements. That is, developers have to make an existing application accessible. There are many aspects to consider for accessibility, such as Assistive Technologies and standards. Many free assistive technology products are available, but learning how to use them and understanding what to expect from them takes time.

While becoming familiar with these issues (and the design challenges they present) is a good thing, there is one vitally important area of accessibility that has no such barrier: keyboard interaction. Keyboard management alone is seldom a sufficient level of accessibility for an application, but it will always be a minimum requirement, as stated in the Working Draft on ARIA Practices:

It is very important that that your widget be keyboard accessible. In fact, there must be a keyboard equivalent for every mouse operation in your application.

If done properly, keyboard management is also beneficial to users without disabilities. Your power users will benefit from the ability to navigate your application with a few keystrokes instead of constantly switching back and forth between keyboard, mouse, and touch screen.

Focus

The concept of focus, while not new, is the cornerstone of keyboard management. What is perhaps new, or at least not entirely obvious, is just how important focus is to users:

A tenet of keyboard accessibility is reliable, persistent indication of focus. The author is responsible, in the scripts, for maintaining visual and programmatic focus and observing accessible behavior rules. Screen readers and keyboard-only users rely on focus to operate rich internet applications with the keyboard. [W3C Working Draft ARIA Practices]

With Ext JS 5.0.1, we added the necessary styling to the core components that support this requirement. We additionally provided Sass variables to allow themes to easily adjust the presentation of focus.

Keyboard Input

The concept of focus is all about keyboard input. When the user types on the keyboard, the key presses are directed to the currently focused element. This may be an obvious thing like an input element, but is not limited to such elements. For example, if a div element is assigned a tabIndex and then gets the focus, keyboard events will be delivered to that element. Unlike the input element, however, there is no default action associated with these events.

Focusability

It makes sense for many components to receive focus. The focusable property of Ext.Component indicates that the component is able to receive focus. This is typically due to the DOM associated with the component (such as the input element of a TextField).

A component’s ability to receive focus is determined by the DOM it produces upon render. Many elements are naturally able to receive focus (such as an anchor or input element). Elements that do not receive focus by default can use the tabIndex attribute.

When a component has an appropriate DOM structure, it should set the focusable class property to true. This instructs the component to listen for focus and blur events. Because a component can contain many elements, such components may also need to implement the getFocusEl method in order to return a reference to the component’s focusable element. This is the primary element by default.

Changing Focus

Focus can move between elements due to mouse clicks or key presses. When a mousedown event occurs on a focusable element, the browser’s default action is to give it the focus. The keyboard, however, provides multiple ways to change focus.

The primary means of changing focus via keyboard is the TAB key (optionally modified by SHIFT). The TAB key moves the focus to the “next” tabbable element. If SHIFT is also pressed, focus instead moves to the “previous” tabbable element. Notice that the word used here is tabbable and not focusable. Some elements may be focusable programmatically or via mousedown events, but are not reachable by the TAB key.

In some cases, the standard requires the use of the arrow keys (LEFT, RIGHT, UP and DOWN) to navigate between child items. This is the case in special containers such as toolbars and menus, but more on those later.

Consequences of Changing Focus

When focus changes, many important side effects come into play. The most obvious are aesthetic, but there are others:

  • Binding – Valid input values with two-way bindings are written back.
  • Collapsing – ComboBoxes and other picker fields may have a floating picker to hide.
  • Delegation – When some components receive focus, they immediately transfer (delegate) the focus to another. For example, see the defaultFocus config.
  • Editing – When used in editors (such as grid cell editors), fields write back their value when losing focus.
  • Validation – Input validation is performed when leaving the field.

Most of these actions are directed at the component that is losing the focus. In DOM terms, that is the component that is being blurred.

Blur Grows Up

In previous versions of Ext JS, the blur event was indeed the event that triggered the aforementioned side effects. In many cases, however, the blur event was not well suited to the task and the framework had to compensate. This was partially due to the fact that focus and blur events do not bubble. The only way to process these events for multiple elements is to add listeners for both events to each and every element. More problematic than bubbling is the fact that Firefox has never properly reported the relatedTarget for these events.

The DOM standards are evolving to correct for this inadequacy by way of the new focusin and focusout events. These events are not universally supported, and even if they were, they would not account for floating components (such as a menu owned by a button). What is needed are events that bubble like focusin and focusout, but also understand the Ext JS component hierarchy.

focusenter and focusleave

These new component events, focusenter and focusleave, are designed to solve these issues. To see them in action, let’s look at this demo:

We have a component hierarchy like this:

  • window
    • tbar
      • A (button)
      • B (button)
      • C (button)
    • bbar
      • X (button)
      • Y (button)
      • Z (button)

As we interact with the buttons, we can see the events in the console:

1. Click button A
--> enter A from ext-element-1
--> enter tbar from ext-element-1
--> enter window from ext-element-1
2. Press RIGHT arrow (focus moves to B)
<-- leave A to B
--> enter B from A
3. Press TAB (focus moves to X)
<-- leave B to X
<-- leave tbar to X
--> enter X from B
--> enter bbar from B

In step 1, we see the focusenter event arrive at button A, then bubble up to the tbar, and finally the window. The navigation to button B is inside the tbar so these events do not reach the tbar or the window (since focus is not entering or leaving them). Finally, when we TAB to button X, the focus does leave the tbar and enter the bbar, but remains inside the window component.

The demo also assigns menus to the buttons. If you open these menus and focus the menu items, you will see that they are treated as children of their owning button. This is true even though the menu elements are rendered to the document body and thus are outside of the DOM hierarchy for the button.

The messages may differ slightly on the first pass versus repeating the steps due to focus delegation of toolbars, but the key thing to note with these events is that they will always supply the “related” component.

onFocusEnter and onFocusLeave

These new component methods are called when focus enters or leaves the component. If you have custom components or views that contain logic in response to focus or blur, you may want to consider moving that logic to these methods. Processing focus and blur is still supported of course, and even useful in some cases. However, if you need to create child components, and especially if they are floating components, then these new methods will likely provide more appropriate timing.

Focus and Containers

Most of the time, users press TAB and SHIFT+TAB to navigate between components. In some cases, however, the standards require the use of LEFT, RIGHT, UP and DOWN arrow keys. For example, in containers such as Menus, Toolbars and RadioGroups, you are expected to enter and exit via a single TAB key press. This helps users navigate the page more quickly and not get bogged down by tabbing through a potentially large set of toolbar buttons.

Ext JS provides this support in the FocusableContainer mixin. This mixin also tracks the previously focused item and restores it when focus returns. To ensure that TAB properly departs the container and that focus is restored on return, this mixin manages the tabIndex of its child items.

Staying Focused

It is extremely important to maintain the focus consistently, and provide logical focus transitions to ensure a productive workflow. For example, when opening a new form it is advisable to place focus on the first input field, so the user could start typing right away without having to navigate to that field.

There are other times when focus needs to be set programmatically, e.g. when using Ext.Msg to display a Yes/No prompt. Whenever this kind of intervention is required, it is important to also restore the focus to its previous location whenever possible. While there is logic in the Window class to assist with restoring the focus, if you need to manipulate the focus, don’t forget that you may need to undo the process.

Masking

Masking is another situation in which focus must be manipulated with care. For example, if a panel has a button that causes an AJAX request to the server, it is often appropriate to mask the panel to prevent further button presses until the request completes. The masking element alone is sufficient to prevent mouse clicks, but to block keyboard access to the panel’s content, more is required.

When the mask is shown, all of the child items are temporarily made untabbable (by setting tabIndex to -1). In addition, if the focus was inside the masked component, the focus is moved to the mask. Assuming the previously focused item is still around when the mask is removed, focus is restored to said item. Child item tabbability is also restored.

Conclusion

With all the attention we pay to touch interfaces today, it is easy to get the impression that touch has replaced all previous interfaces. Developers aren’t the only people still using the keyboard. Our users depend on it as much as we do. If our apps can be driven from the keyboard, we give our users the productivity and efficiency they want. We also open the door for people with disabilities.

The best part is that you can always tell how well things are going: just count the number of times you have to reach for the mouse or touch the screen to get a task done.

best-prac.jpg 6 Comments   Read more

Best Practices for Building HTML5 Applications

JavaScript has enjoyed a long and storied history since its creation in 1995. As a prototype-based scripting language, JavaScript quickly became useful as a mechanism to implement dynamic logic and interactivity on web sites — and combined with the latest features of HTML5 and CSS3, JavaScript has evolved into a required technology for delivering powerful web applications.

But web development also has a frustrating past, and for many software developers JavaScript and CSS remain tricky to learn. Older Internet browsers delivered wide variations in the ECMAScript and CSS specifications which led to many problems creating applications compatible across browsers and devices. Rather than trying to implement this cross-browser code themselves, developers often turned to JavaScript libraries like Prototype (2005), jQuery (2006) and Ext JS (2007).

Over the years, Sencha has evolved with the needs of enterprise web applications, and our customers look to us for direction and leadership as these web technologies continue to advance.

Defining Best Practices

HTML5 has proven itself to be a reliable and powerful platform for building robust applications across a variety of devices. However, as web technology continues to evolve at a rapid pace, it can be difficult for developers to stay on top of the latest tools and techniques.

Our customers frequently ask our advice on the subject of “best practices” — and while we’ve covered many of these concepts in past webinars and at SenchaCon, we wanted to start 2015 by releasing a more robust collection of recommendations for building enterprise web applications with JavaScript and HTML5.

A lot of this advice is used internally at Sencha and certainly applies to building applications with Sencha frameworks — but this JavaScript style guide can also help teams building applications with any framework, or even just vanilla JavaScript. These recommendations are based on our own experiences, as well as direct interaction with our enterprise customers.

The overall goal for this document is to help you evaluate what Sencha considers to be the important aspects of “quality” code, and ultimately create your own readable, maintainable and scalable JavaScript projects. These best practices stand as a baseline from which your teams can implement your own strategy for building a high quality JavaScript codebase. We encourage you to fork our GitHub repo!

Hear More from the Experts

To go a step further, Sencha has organized a panel of experts to discuss a variety of topics in our January webinar titled Best Practices for Building HTML5 Applications. Join thought leaders from Sencha, Netflix, Salesforce, Apigee, Swarm Online and Modus Create as we examine:

  • Strategies for building scalable and maintainable code
  • Approaches to consider when building web applications for mobile or desktop
  • Which tools and resources the experts recommend

Best Practices for Building HTML5 Applications

January 22, 2015

10:00am PST

Best Practices for Building HTML5 Applications

5 Comments   Read more

Creating Native Windows 8 Apps with Ext JS 5

Creating Native Windows 8 Apps with Ext JS 5Microsoft has a long and storied history in the field of web development. After Internet Explorer (IE) effectively won the first ”browser wars“ of the late 1990s and early 2000s, development on IE stagnated. IE6 was released in 2001 and quickly amassed 90% of the browser market share at that time — but IE soon received a poor reputation because it was not updated to support the newly emerging web standards in the years that followed. The subsequent ”browser wars“ of the late 2000s, coupled with the introduction of mobile devices, quickly eroded IE’s dominant market share.

But in recent years Microsoft has fought hard to improve its reputation as a leader in the tech community, specifically under the banner of HTML5. Microsoft first began touting the benefits of HTML5 back in 2010, and soon added their first HTML5 features in IE 9.

Microsoft’s support for HTML5 has continued to grow and expand since then (read the Sencha whitepaper). With the arrival of Windows 8 in 2012, Microsoft elevated web technologies as first-class development options to build native Windows applications. For the first time, developers could use JavaScript, HTML, and CSS to build and distribute as native Windows applications without the use of special wrappers or compilers.

As a developer excited by all things HTML5, I jumped at the chance to begin building Windows 8 applications. I even spoke about creating Windows 8 applications with Ext JS at SenchaCon 2013… but I quickly discovered how Windows 8 apps built with HTML5 were very different from those running in a browser.

Fast forward to 2014, and Sencha has released Ext JS 5. Among the many new features is a little known improvement that makes building Windows 8 applications completely seamless. Let’s take a quick look at how Windows 8 applications are different from basic web apps, and then dive into how Ext JS 5 makes it easier to develop Windows 8 apps.

Windows 8 Applications

Windows 8 originally shipped with IE10 as its browser, and now Windows 8.1 comes with IE11. According to multiple sources (HTML5Test.com, HTML5Readiness.com, and even Sencha) both IE10 and IE11 have pretty awesome support for HTML5 — which is important because native Windows 8 applications built with web technology effectively use the same rendering and JavaScript engines as IE10/11.

HTML5test.com score over the years.

However, because native Windows 8 applications can access the native Windows APIs, Windows 8 applications built with HTML5 are subject to the security model of the Windows shell. This security policy restricts many practices JavaScript developers take for granted — things like using the window API and dynamically adding HTML. But because many JavaScript frameworks handle DOM operations under-the-hood (Ext JS included), building native Windows 8 applications with your favorite JavaScript framework has historically been a challenge.

Ext JS 5.0.1 and the ext-win8 Package

With the recent release of Ext JS 5.0.1, Sencha has committed to making Ext JS comply with the Windows 8 security policy. This process involves two important parts:

  • Ext JS 5.0.1 was carefully crafted to include a special hook that, when configured, elevates restricted JavaScript and DOM operations into the proper execution context.
  • We created a special Sencha Cmd package containing the configured hook (ext-win8) that is incredibly easy to install.

As a result, you can build native Windows 8 applications using Ext JS, just as you would any other web application.

To install the ext-win8 package, simply add ”ext-win8“ to your application’s app.json file under ”requires“.

//…
"requires" : [ "ext-win8" ],
//...

Then use Sencha Cmd to refresh your application:

sencha app refresh --packages
//or
sencha app build development

Sencha Cmd will then download the ext-win8 package from our CDN and install it into your machine’s local repository (e.g. /Users/arthurakay/bin/Sencha/Cmd/repo/pkgs/).

As part of the refresh/build process, Sencha Cmd will copy ext-win8 to your application (or workspace) and rebuild your application’s dependency chain, ultimately including the necessary Windows 8 hooks.

Watch the following short video to see how it all works:

The sample application from the video is also available on GitHub.

Conclusion

By embracing HTML5, Microsoft has opened new doors for developers and provided access to new markets for HTML5 developers. Equally important, Microsoft has shifted from laggard to leader in HTML5 support—and in so doing has signaled strong support for the idea of multi-device, multi-platform, universal apps.

With Ext JS 5 fully primed, now is the time for developers to take a fresh look at the Windows 8 platform to evaluate how HTML5 creates new options for their businesses and their customers.

creating-native-windows-8-apps-with-ext-js-5.png 6 Comments   Read more

Top Support Tips

New Framework, New Doctype

by Greg Barry

In Ext JS 5, we support IE 8+, so we no longer encourage users to use the strict HTML 4 doctype. We now recommend using an HTML5 doctype. We also recommend the X-UA-Compatible meta tag to ensure Internet Explorer does not activate “Compatibility Mode” because this mode is not supported by Ext JS.

The following code snippet shows the ideal doctype and head for Ext JS 5.

<!DOCTYPE html>
<html>
<head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>

You can find more information about recent changes in Ext JS in our What’s New in Ext JS 5 guide.


Overhaul your Overrides

by Greg Barry

Overrides can be a very helpful tool to expand or change functionality on core classes without having to modify the framework’s source code. Ext JS 4.1 brought about a new way to create these overrides for the framework. This new declarative-based override works well within the foundational principles of Ext JS 4 and Ext JS 5. These overrides can then be placed in your Sencha Cmd generated overrides folder. The overrides folder allows Cmd to automatically include the overrides. For instance, if you use Ext.grid.Panel, you can create a file at overrides/grid/Panel.js. This should be automatically included after bootstrap is refreshed via sencha app build, sencha app watch, or sencha app refresh.

This method of overriding can be seen throughout the framework within our own internal code style. Examples of internal overrides in action include: theming, localization, RTL, and much more.

That said, we still see old overrides from Ext JS 3 being incorporated into applications using newer frameworks. This creates the potential for timing issues when applying them to your new application architecture.

The preferred method of generating an override is as follows:

Ext.define('MyApp.overrides.panel.Panel', {
        override: 'Ext.panel.Panel',
        close: function() {
                console.log('My Change to Close');
                this.callParent(); // call the original method
        },
        helloWorld: function(){
                console.log('Hello World');
        }
});

Let’s go over the syntax:

  1. First, define your override with an appropriate namespace for your application’s overrides folder.
  2. Add the override config and give it a value equivalent to the class you want to override. In this example, we’re overriding Ext.panel.Panel.
  3. Add the function you want to override. You’ll need to make sure you keep all of the relevant pieces. In this case, I’ve only changed the close function by adding a console log. If you were to create a panel and then do panel.close(), you will receive a console message saying, “My Change to Close”.


    Note: In your overridden method, you should execute this.callParent() if you need the overridden method to be called including the methods of any base classes.
  4. Add a new function altogether. As you may imagine, Ext.panel.Panel does not contain a “helloWorld” method. However, I’ve just added it via this override. Now, creating a panel and issuing panel.helloWorld() will result in logging the message “Hello World”.

As you can see, overrides are a powerful utility for customizing the framework for your application. If your overrides are still formatted in the Ext JS 3 manner, it may be time for an overhaul.

You can read more about the define mechanism here.


callParent(), a Little Bit Less

by Don Griffin

callParent is a method provided by the Sencha Class System (common to Ext JS and Sencha Touch) that is used to call methods in your base class. This is commonly done when you derive from a framework class and override a method it provides such as onRender. When you invoke callParent from a method that has parameters, you have two ways you can pass along those parameters to the base class method. You could use the shorthand arguments keyword like so:

Ext.define('App.view.MyPanel', {
        extend: 'Ext.panel.Panel',
        onRender: function (parentNode, index) {
                this.callParent(arguments);
        }
});

Or, you could explicitly pass these arguments in an array literal:

onRender: function (parentNode, index) {
        this.callParent([ parentNode, index ]);
}

The differences may seem minor, but when you use the Sencha Cmd 5 new optimizations for callParent, performance improvements can be profound. With the optimizer enabled, these two methods are optimized as follows:

onRender: function (parentNode, index) {
        Ext.panel.Panel.prototype.onRender.apply(this, arguments);
}
 
onRender: function (parentNode, index) {
        Ext.panel.Panel.prototype.onRender.call(this, parentNode, index);
}

In the second case, the optimizer is able to use the call method on the JavaScript Function instead of apply. We also avoid using arguments. Both of which are well-known high performance no-no’s. It turns out that we even avoid creating the array literal. Obviously, just enabling the optimization is helpful, but in code where performance is most critical, it is worth replacing arguments with the explicit array.

If you have questions, visit the forum.

20131111-top-support-tips.jpg 2 Comments   Read more

Training Tip: Developing Apps in a Multi-Device World

I work for Sencha as a technical trainer, which means I travel a lot. Whenever I go through security at the airport, I have to pull out all my electronics. I’m always so amazed how many devices I have with me — a laptop, a tablet, an e-reader, my portable game console, a smartwatch, maybe my camera and of course my phone. Be honest, how many devices do you have with you right now while you’re reading this article — 3? 4? 5 or more?

We live in a multi-device world. You all have the same devices I do. Others have cars with smart navigation systems. All these devices have screens and often an internet connection. They come in different flavors — but they all run apps.

Multi-device world

As you think about developing apps, which of these different devices will you target? Will you develop a native app for every device? That’s gonna be a pain to maintain, and it will cost a lot. So ideally, you would like to build a single app that runs on every device. To do this, you will have to look at the differences between all these devices.

Various Screen Sizes

Sencha Touch Multi-device world

The first thing you probably noticed is the screen size. Looking back, the days when I developed websites for 800×600 and 1024×768 are over. Nowadays, there are so many different resolutions that you can’t keep track of them all. Different devices have more or less space available on the screen, so it makes sense to design your application differently.

Think about an email application that runs on your phone and only displays a list. When you tap on an email subject, it displays the email. Now, when you run this app on a tablet, suddenly the list with emails is docked to the left, and all the email bodies are always visible in the center of your screen — simply because there is more space available.

One solution for building interfaces like these is responsive design. With techniques like CSS3 media queries, flexible grids, images and relative units, you can have a website respond to the user’s screen size.

With the release of Ext JS 5, Sencha supports responsive design. To implement responsive design, you don’t need to code media queries in your CSS, you can write Sencha configurations, just like you’re used to:

plugins: ['responsive'],
responsiveConfig: {
        wide: {
                height: 100
        },
        tall: {
                height: 20
        }
}

See more information in the Sencha docs.

In Sencha Touch, we deal with various screen sizes by creating device profiles. Device Profiles are great because not only can you create different views per device, you can also create different functionality:

Ext.define('MyApp.profile.Tablet', {
        extend: 'Ext.app.Profile',
 
        config: {
                name: 'Tablet',
                views: ['Main']
        },
 
        isActive: function() {
                return Ext.os.is('Tablet');
        }
});

See more information in the Sencha docs.

Different Operating System, Different Browser

Assuming all these devices can run a browser, another big difference across platforms is the operating system and the browser engine. Windows, Linux, Android, Mac OS X, iOS use different browser engines: Webkit (Safari, Google Chrome), Trident (Internet Explorer), Gecko (Firefox) or others.

Often, websites and web applications look and behave differently on each browser or browser and OS combination. This is why you need to test your application on multiple devices. Or, you can use a framework, such as Ext JS 5 or Sencha Touch. A good framework can make a developer’s life easier. We can focus on the things we love like implementing our business logic and creating app ideas. We let the framework deal with all the challenges and pitfalls of app development for different browsers on different platforms.

User Input

All these devices vary in the types of user input they support. Does your device support touch and gesture input? Mouse and keyboard? Maybe you run your app on a device with a stylus? Your smart TV app might require a remote control. Or maybe you want to go totally overboard and create Minority Report / Xbox Kinect like gestures? For example, you could develop an app in JavaScript and implement support for the Leap Motion Controller by using their APIs. See this article for details: Using the Leap Motion Controller with Sencha Touch.

Ext JS 5 and Sencha Touch have built-in touch and gesture support. You can use: tap, drag, swipe, pinch and rotate. But you do need to think about the best way to implement them. Double click and hover events might work best on a desktop computer. Swipe and pinch gestures work best on touch devices. Your buttons might need to be bigger and have more white space on touch devices. You’ll need to wear your designer hat and think about the best UI.

Features Sets

All these devices come with different feature sets. Obviously, your camera can take pictures or videos. Your TV has a cable connection or could record live TV. But there is more, on what type of internet connection are you running? Is your device location-aware using GPS? How much data can you store?

You also need to know whether there are APIs available for your device. For example, on phones and tablets, you might want to port your Ext JS 5 or Sencha Touch app with Adobe PhoneGap or Apache Cordova to build a hybrid app. By adding a native wrapper, you can get access to various device APIs. Think about the phone camera, calendar, contacts or push notifications.

There are lots of great Cordova plugins available. You could use a QR code reader plugin, or you could port your application to Google Glass? See this article for more details: Developing for Google Glass with Sencha Touch.

To create a hybrid build, you can use Sencha Cmd, in combination with Adobe PhoneGap or Apache Cordova on top of Node JS. Sencha has built-in integration, so you can use commands like these on your command line:

//for initializing Phonegap:
sencha phonegap init com.sencha.myapp MyApp
//for initializing Cordova:
sencha cordova init com.sencha.myapp MyApp
//..and then, build!
sencha app build native

Data Security

Sencha Space

The last multi-device development challenge I would like to discuss is data security. Where do you save your data and is it secure?

With HTML5 browser capabilities like cookies, local storage, local databases and app cache, the browser may contain sensitive data, such as login information, website or purchase history, or data from your email client or CRM. It’s important to protect this data, so you don’t have to worry if your device is lost or stolen.

You can easily deploy your apps in Sencha Space, which provides a secure delivery platform. When a device is lost or stolen, it’s possible to remotely revoke user/device access or wipe the data. You can monitor, audit and report on app, device and user activity and all apps deployed within Sencha Space can communicate with each other.

Conclusion

Differences in platforms, screen sizes, user input and feature sets can make it hard to build a good looking and performing cross platform app. HTML5 is the language that every modern device understands. With Sencha Touch, Ext JS and Space, you have everything you need to build apps for multiple devices.

Do you already have an Ext JS 4 application that you’d like to optimize for “mobile” use? Sencha is offering Ext JS 5 courses online and in Europe and the US. Take a look at the training schedule and sign up for a class. You can get 10% off upcoming Ext JS 5 training classes — use the code: TrainingTip.

20140702-multi-device-world.jpg No Comments   Read more

Getting Started with GWT Super Dev Mode

Super Dev ModeIf you’ve been using GWT in the last few months, you’ve undoubtedly noticed that various browsers have been removing support for classic Dev Mode. This change has been a long time coming. It helps to ensure better performing browsers and plugins, but puts a kink in debugging GWT applications. The future is in Super Dev Mode, so we’ve been testing it regularly, making sure that GXT applications will work correctly in it, and improving the development process.

As of GWT 2.6.1, supported by GXT 3.1, Super Dev Mode works in all browsers on all operating systems. The next version of GWT will continue to streamline the development workflow, but until it gets here, we’ve been working on the Eclipse plugin to streamline getting Super Dev Mode running in your project.

Any project that uses Super Dev Mode must use a linker that supports it. Most projects use the default linker, and up until GWT 2.6.1, that is the ‘std’ linker, which loads the content of the application in an iframe. As of GWT 2.7, this default will change to xsiframe, but for now, we must modify our application to use it:


Using Super Dev Mode or SDM means running two servers, one for the web application and one for the Code Server that compiles classes for SDM when the compile button is pushed on the web page or in the bookmark. So in the future, classic Dev Mode is being modified to include a
-superDevMode argument to start the SDM Code Server for SDM debugging. This means having classic Dev Mode arguments but with SDM debugging all in one launch configuration package. To back port this feature in Google Plugin for Eclipse, a legacy jar is being added and used to override current Dev Mode bootstrapping to provide a seamless transition to the SDM experience.

Start by right clicking on a project and running the “Web Application (GWT SDM)” shortcut, which will create a new launch configuration.

Super Dev Mode

This produces a Development Mode tab that contains a quick link to load the browser for debugging.

Super Dev Mode

Once the browser initializes, it will start the first Super Dev Mode compiling.

Super Dev Mode

While the Code Server provides bookmarks for “Dev Mode on”, “Dev Mode off” and “Compile”, there is a new compile button overlayed on the application that can conveniently compile the application after a change. It’s found in the lower right hand corner of the App. This will recompile and reload the application, and the output can be viewed in Eclipse console.

Super Dev Mode

Changing around launch configuration is done by editing the application launch configuration. Both “Super Development Mode” or “Classic Development Mode“ can be used to debug the application, although Classic Dev Mode will have to use the older browsers.

Super Dev Mode

At this point, you can make changes to your application code and see them in the browser by clicking the “GWT” compile button again. You can also simply refresh the page to reload it without recompiling — handy for testing the app when you aren’t actively making code changes.

Check out this screencast demonstrating the steps above:

At the time this article was written, this new addition to the plugin hadn’t yet shipped, but it will be going out soon. The improvements will make it easier to get started with Super Dev Mode in 2.5.x to 2.6.x+ and streamlines the transition to Super Dev Mode. GWT 2.7 also has more changes to enhance the performance and development experience as well.

20140702-gwt-super-dev.jpg 19 Comments   Read more

Creating Custom Layouts in Ext JS and Sencha Touch

custom layouts in Ext JS and TouchThe Layout system is one of the most powerful and unique parts of the Sencha frameworks. Layouts handle the sizing and positioning of every Component in your application, so you don’t need to manage those pieces manually. Ext JS and Sencha Touch have many similarities between their Layout classes, and our own Ivan Jouikov recently analyzed them in detail in this Sencha blog post.

Having said that, most Ext JS and Sencha Touch developers have probably never looked under the hood of the Layout system. Sencha frameworks deliver the most common application layouts out of the box, so unless your application required more exotic functionality, it is unlikely you have investigated the inner workings of the Layout system.

Imagine for a moment that your company needed to display UI elements for your application using a “3D Carousel”. None of the standard Sencha layouts offer this sort of ability — so how might you approach this problem?

Choosing a Base Class

When developing any custom component in Ext JS and Sencha Touch, the first step should always be to consider which base class is the best choice to extend. In this situation, we need a layout that can house items in 3D space. Therefore, we can start pretty low on the Layout inheritance chain because we don’t require any specific functionality beyond managing items. In this case, Ext.layout.container.Container (Ext JS) and Ext.layout.Default (Sencha Touch) make the most sense.

In Ext JS, the Layout system is responsible for manually managing many of the size and positioning calculations, primarily because Ext JS supports legacy browsers that don’t support some modern CSS features like Flexbox. As a result, Ext.layout.container.Container includes a number of methods like calculate(), getContainerSize() and getPositionOffset() which our 3D carousel layout will still need to override to lay out its children.

It is also important to note that the Ext JS layouts perform “runs”, and each run may manage multiple “cycles”. For example, Box layouts configured with stretchmax would require at least two cycles, in which the layout would first determine the maximum size of each child component, and then stretch all children of the layout to the same size via a second cycle. Operations causing large numbers of layout runs and/or cycles to occur (e.g. adding or removing many items) may want to preemptively suspend layouts to improve performance, resuming layouts only after the operations are complete.

By contrast, Ext.layout.Default in Sencha Touch allows the browser to handle the positioning and sizing of most items in the layout via CSS (because Sencha Touch only supports modern browsers, all of which implement CSS Flexbox). Therefore, Ext.layout.Default contains mostly methods relating to the addition, removal and repositioning of child items.

Now that we understand which classes we should extend for our new “3D Carousel” layout, let’s explore the necessary steps to physically build it.

CSS3 Transforms and Other Magic

In order to build a “3D Carousel”, we will need to use some advanced CSS 3D transforms such as transform, transition, rotateX/rotateY and translateZ. CSS 3D transforms can be very complicated, but in a nutshell we need to do the following things for our new Sencha layout:

  • Apply a perspective and transform to the parent container (making it appear 3D)
  • Apply a transform to the child components in the layout (rotating them around the 3D shape to form its sides)
  • Apply a transform to an inner DOM element of the parent container (to physically rotate the 3D shape as the user interacts with it)

As you might expect, the actual DOM generated by Ext JS and Sencha Touch is a bit different, so while the approach taken in the exercise is the same in both frameworks, the resulting CSS is slightly different. The additional CSS we need to include with our new “3D Carousel” layout looks like this (for Sencha Touch):

.x-layout-carousel {
    -webkit-perspective : 1500px;
    -moz-perspective    : 1500px;
    -o-perspective      : 1500px;
    perspective         : 1500px;
    position            : relative !important;
}
 
.x-layout-carousel .x-inner {
    -webkit-transform-style : preserve-3d;
    -moz-transform-style    : preserve-3d;
    -o-transform-style      : preserve-3d;
    transform-style         : preserve-3d;
}
 
.x-layout-carousel.panels-backface-invisible .x-layout-carousel-item {
    -webkit-backface-visibility : hidden;
    -moz-backface-visibility    : hidden;
    -o-backface-visibility      : hidden;
    backface-visibility         : hidden;
}
 
.x-layout-carousel-item {
    display  : inline-block;
    position : absolute !important;
}
 
.x-layout-carousel-ready .x-layout-carousel-item {
    -webkit-transition : opacity 1s, -webkit-transform 1s;
    -moz-transition    : opacity 1s, -moz-transform 1s;
    -o-transition      : opacity 1s, -o-transform 1s;
    transition         : opacity 1s, transform 1s;
}
 
.x-layout-carousel-ready .x-inner {
    -webkit-transition : -webkit-transform 1s;
    -moz-transition    : -moz-transform 1s;
    -o-transition      : -o-transform 1s;
    transition         : transform 1s;
}

The CSS for our Ext JS layout looks nearly identical, with only minute changes to the CSS selectors.

In both Sencha Touch and Ext JS, we will have to modify some additional CSS during runtime to respond to the user’s interaction with our “3D Carousel”. Let’s first extend our base layout classes, and then explore how to add the interactive functionality.

Extending the Base Layout Classes

When we first extend Ext.layout.Default in Sencha Touch, we primarily want to add some configuration options for the look and feel of our new “3D Carousel”, as well as some utilities for correctly positioning the child items within this layout.

Our extension initially looks like this:

Ext.define('Ext.ux.layout.Carousel', {
        extend : 'Ext.layout.Default',
        alias  : 'layout.carousel',
 
        config : {
                /**
                 * @cfg {number} portalHeight
                 * Height of the carousel, in pixels
                 */
                portalHeight : 0,
 
                /**
                 * @cfg {number} portalWidth
                 * Width of the carousel, in pixels
                 */
                portalWidth  : 0,
 
                /**
                 * @cfg {string} direction
                 * 'horizontal' or 'vertical'
                 */
                direction    : 'horizontal' //or 'vertical'
        },
 
        onItemAdd : function () {
                this.callParent(arguments);
                this.modifyItems();
        },
 
        onItemRemove : function () {
                this.callParent(arguments);
                this.modifyItems();
        },
 
        modifyItems : function () {
                //calculate child positions, etc
        }
});

Aside from the config object, we see three methods: onItemAdd(), onItemRemove(), and modifyItems(). The first two methods are simple overrides of Ext.layout.Default which allow us to modify the positioning of child items upon addition/removal, and modifyItems() is a new method for calculating the fancy CSS 3D transforms.

The action inside the Layout system ultimately comes alive when the Layout classes assign their container (from Ext.layout.Default):

setContainer: function(container) {
        var options = {
                delegate: '> component'
        };
 
        this.dockedItems = [];
 
        this.callSuper(arguments);
 
        container.on('centeredchange', 'onItemCenteredChange', this, options, 'before')
                .on('floatingchange', 'onItemFloatingChange', this, options, 'before')
                .on('dockedchange', 'onBeforeItemDockedChange', this, options, 'before')
                .on('afterdockedchange', 'onAfterItemDockedChange', this, options);
},

For our layout extension, we need to piggyback on this method in order to do some further initialization:

Ext.define('Ext.ux.layout.Carousel', {
 
        //...
 
        setContainer : function (container) {
                var me = this;
 
                me.callParent(arguments);
 
                me.rotation = 0;
                me.theta = 0;
 
                switch (Ext.browser.name) {
                        case 'IE':
                                me.transformProp = 'msTransform';
                                break;
 
                        case 'Firefox':
                                me.transformProp = 'MozTransform';
                                break;
 
                        case 'Safari':
                        case 'Chrome':
                                me.transformProp = 'WebkitTransform';
                                break;
 
                        case 'Opera':
                                me.transformProp = 'OTransform';
                                break;
 
                        default:
                                me.transformProp = 'WebkitTransform';
                                break;
 
                }
 
                me.container.addCls('x-layout-carousel');
                me.container.on('painted', me.onPaintHandler, me, { single : true });
        },
 
        onPaintHandler : function () {
                var me = this;
 
                //add the "ready" class to set the CSS transition state
                me.container.addCls('x-layout-carousel-ready');
 
                //set the drag handler on the underlying DOM
                me.container.element.on({
                        drag      : 'onDrag',
                        dragstart : 'onDragStart',
                        dragend   : 'onDragEnd',
                        scope     : me
                });
 
                me.modifyItems();
        }
 
});

After we assign the layout’s container internally, we must wait until the container physically renders in order to assign event handlers to its underlying DOM. Next, we need to fill in the functional gaps for transforming the child items managed by this layout:

Ext.define('Ext.ux.layout.Carousel', {
 
        //...
 
        modifyItems : function () {
                var me = this,
                        isHorizontal = (me.getDirection().toLowerCase() === 'horizontal'),
                        ct = me.container,
                        panelCount = ct.items.getCount(),
                        panelSize = ct.element.dom[ isHorizontal ? 'offsetWidth' : 'offsetHeight' ],
                        i = 0,
                        panel, angle;
 
                me.theta = 360 / panelCount;
                me.rotateFn = isHorizontal ? 'rotateY' : 'rotateX';
                me.radius = Math.round(( panelSize / 2) / Math.tan(Math.PI / panelCount));
 
                //for each child item in the layout...
                for (i; i < panelCount; i++) {
                        panel = ct.items.getAt(i);
                        angle = me.theta * i;
 
                        panel.addCls('x-layout-carousel-item');
 
                        // rotate panel, then push it out in 3D space
                        panel.element.dom.style[ me.transformProp ] = me.rotateFn + '(' + angle + 'deg) translateZ(' + me.radius + 'px)';
                }
 
                // adjust rotation so panels are always flat
                me.rotation = Math.round(me.rotation / me.theta) * me.theta;
 
                me.transform();
        },
 
        transform : function () {
                var me = this,
                        el = me.container.element,
                        h = el.dom.offsetHeight,
                        style= el.dom.style;
 
                // push the carousel back in 3D space, and rotate it
                el.down('.x-inner').dom.style[ me.transformProp ] = 'translateZ(-' + me.radius + 'px) ' + me.rotateFn + '(' + me.rotation + 'deg)';
 
                style.margin = parseInt(h / 2, 10) + 'px auto';
                style.height = me.getPortalHeight() + 'px';
                style.width = me.getPortalWidth() + 'px';
        },
 
        rotate : function (increment) {
                var me = this;
 
                me.rotation += me.theta * increment * -1;
                me.transform();
        }
});

In our case, there’s a fair amount of complex math to determine the proper placement of each item, as well as the need to manually update the CSS transform values on the container itself.

Finally, we need to add our event handlers to capture when the user interacts with our “3D Carousel”:

Ext.define('Ext.ux.layout.Carousel', {
        //...
 
        onDragStart : function () {
             this.container.element.dom.style.webkitTransitionDuration = "0s";
        },
 
        onDrag : function (e) {
                var me = this,
                        isHorizontal = (me.getDirection().toLowerCase() === 'horizontal'),
                        delta;
 
                if (isHorizontal) {
                        delta = -(e.deltaX - e.previousDeltaX) / me.getPortalWidth();
                }
                else {
                        delta = (e.deltaY - e.previousDeltaY) / me.getPortalHeight();
                }
 
                me.rotate((delta * 10).toFixed());
        },
 
        onDragEnd : function () {
             this.container.element.dom.style.webkitTransitionDuration = "0.4s";
        }
 
});

These event handlers simply evaluate how far the user has dragged their mouse across the carousel, and then update the CSS transition.

The full Sencha Touch code for this class can be found here. The code for Ext JS, which extends Ext.layout.container.Container, is again very similar but does have minute API changes due to the differences between frameworks. The Ext JS code for this example can be found here.

Reviewing Ext.ux.layout.Carousel

Let’s take a moment to step back and review what just happened.

We chose to extend the Sencha Touch class Ext.layout.Default because our new “3D Carousel” layout only needed to inherit the baseline functionality of the layout system. Next, we added overrides for onItemAdd(), onItemRemove(), and setContainer() to append some runtime configuration of our layout. Finally, we implemented a few utility methods and event handlers to physically manage the positioning of the child items in our layout.

Although the idea of a “3D Carousel” is a whimsical example of what can be built using Sencha Touch or Ext JS, the point here is that building creative new layouts in Sencha applications is actually really simple. The key is understanding how layouts are initialized and what happens during runtime — and the underlying framework code is far less complicated than you might think. And while the Layout system is a bit different under the hood between Sencha Touch and Ext JS, the general approach is exactly the same.

Please note: this is actually just a tech demo, and I can’t guarantee my code works on every browser. The fact that I’m using CSS3 transforms already means I’ve excluded older versions of several browsers, so please don’t try to use this in production.

Other interesting examples of customized layouts include this Sencha Fiddle by Sencha Support engineer Seth Lemmons involving a circle menu, and this video of a custom navigation component by Andrea Cammarata, Sencha Professional Services engineer.

20140702-custom-layout.jpg 6 Comments   Read more

Designing Responsive Applications with Ext JS

Ext JS 5 Executive Dashboard App

In today’s world, users expect to be able to use web applications not only on their desktop computers, but also their mobile devices, which come in all shapes and sizes. The requirement to make an application so adaptive can seem overwhelming. Fortunately Ext JS 5 provides all the tools needed to make your application conform to any screen size, shape or orientation.

Introducing responsiveConfig

With the new tablet support in Ext JS 5 comes “responsiveConfig”, a powerful new feature for making applications respond dynamically to changes in screen size or orientation. responsiveConfig is enabled using one of two classes:

  • Ext.plugin.Responsive: Adds responsive capabilities to an Ext.Component
  • Ext.mixin.Responsive: Adds responsive capabilities to any other class

Making Components Responsive

For performance reasons, Ext JS Components do not have responsive features enabled by default, so to make a Component responsive you’ll need to use the responsive plugin. Add the responsive plugin to the class body to make all instances responsive, or add it to the instance config to enable responsiveness for a single Component instance:

plugins: 'responsive'

Once you have added the responsive plugin to your Component config, your Component will gain a “responsiveConfig” configuration option. responsiveConfig is simply an object with keys that represent conditions under which certain configs will be applied. For example, suppose your application has a Tab Panel, and you want the Tab Bar to be left aligned in landscape mode, but top aligned in portrait mode. You can use the words “landscape” and “portrait” as keys in the responsiveConfig object to dynamically set the Panel’s ‘tabPosition‘ config in response to device orientation change:

Ext.define('MyApp.view.Main', {
        extend: 'Ext.tab.Panel',
        plugins: 'responsive',
        responsiveConfig: {
                landscape: {
                        tabPosition: 'left'
                },
                portrait: {
                        tabPosition: 'top'
                }
        },
        items: [
                { title: 'Foo' },
                { title: 'Bar' }
        ]
});

Rules

Each key, or “rule”, in the responsiveConfig object is a simple JavaScript expression. The following variables are available for use in responsiveConfig rules:

  • ‘landscape’ – True if the device orientation is landscape (always ‘true’ on desktop devices)
  • ‘portrait’ – True if the device orientation is portrait (always ‘false’ on desktop devices)
  • ‘tall’ – True if ‘width’ is less than ‘height’ regardless of device type
  • ‘wide’ – True if ‘width’ is greater than ‘height’ regardless of device type
  • ‘width’ – The width of the viewport
  • height’ – The height of the viewport

You can combine these variables in a variety of ways to create complex responsive rules. For example, the following responsiveConfig hides a Component if the viewport is less than 768 pixels wide and the viewport’s height is greater than its width:

responsiveConfig: {
        'width < 768 && tall': {
                visible: true
        },
        'width >= 768': {
                visible: false
        }
}

Which Configs Can Be Responsive?

Internally, the framework monitors the viewport for resize and orientation change, and it re-evaluates all of the responsive rules whenever either one of these events occurs. Any matching rules will have setters called for all of their configs. This means that in order for a configuration option to be used with responsiveConfig, it must have a setter. In the above example, we can use “visible” as a responsiveConfig because Ext.Component has a setVisible() method.

Making Classes Responsive

responsiveConfig is most useful for Components, but sometimes you may find the need to make other classes respond to screen size as well. For classes other than Ext.Component, this is accomplished by mixing in Ext.mixin.Responsive. For example, an instance of the following class will have its “foo” config updated whenever the screen shape changes from “wide” to “tall” or vice versa:

Ext.define('MyClass', {
        mixins: ['Ext.mixin.Responsive'],
        config: {
                foo: null
        },
        responsiveConfig: {
                wide: {
                        foo: 1
                },
                tall: {
                        foo: 2
                }
        },
        constructor: function(config) {
                this.initConfig(config);
        },
        updateFoo: function(foo) {
                console.log(foo); // logs "1" or "2" as screen shape changes between wide and tall
        }
});

Try it Out

We wanted to make sure that the new responsive design features of Ext JS could stand the test of a real-world application, so we built an application that leverages responsiveConfig to adapt to a wide range of screen sizes and orientations on both desktops and tablets. The app can be found here.

Try resizing your desktop browser window, or rotating your tablet, and look for the following changes to the application’s presentation and layout:

  • Main navigation is positioned to the left in “wide” mode and to the top in “tall” mode
  • Tab icons are aligned to the top in “tall” mode, and to the left in “wide” mode
  • Tab text is centered in “tall” mode and left aligned in “wide” mode
  • In “tall” mode if the screen becomes too narrow for the navigation bar, an overflow menu tool will display, and the navigation items will display in a menu.

We’re sure that these new features of Ext JS 5 will make the task of developing cross-device applications a lot easier, and we hope you’ll give it a try. Who knows, you might even have fun!

20140701-responsive-apps-preview.jpg 18 Comments   Read more

Deep Dive Into Ext JS 5 Data

Introduction

Ext JS 5 DataWith the introduction of Ext JS 5, we have greatly expanded the capabilities of the Sencha Data Package, which was initially released with Ext JS 4 and Sencha Touch 2. The data package is one of the cornerstones of application development: the oft neglected “M” (for Model) in the buzzing world of “MVC” and “MVVM”. These new capabilities can be seen throughout the entire application development process, from declaring your data model, to presenting your data and validating user input, and finally, saving it back to the server.

In this article, we’ll walk through each of these features. Let’s start at the beginning.

To learn more, join us for the upcoming webinar — Deep Dive into Ext JS 5 Data, Thursday, 7/17 at 10:00am PDT

UPDATE July 18, 2014: Thanks to everyone who attended the webinar! The recording is available here.

New Declarative Features

Typical applications have many classes that make up their data model. With Ext JS 5, we reduced the amount of repetitive, boilerplate code needed in these Model classes. Many of these enhancements are covered in What’s New In Ext JS 5 so I won’t repeat too much of that here.

Fields

It may seem contradictory in this context, but in Ext JS 5, you are no longer required to declare a Model’s fields. The advantage here is that data can be more easily extended, so long as it needs no special processing prior to record creation. It’s not just easier, meaning you have fewer things that you must declare, but it can be faster as well. This optimization occurs because the data is not processed on a per-field basis, unless needed.

While eliminating field declarations is convenient at times and an easy way to eliminate per-field processing, this is not always possible. For example, the defaultValue and convert configs require processing for the field on which they are declared. When adding validators and references on fields, you can still avoid this processing by using the default field type “auto” (and avoiding the configs just mentioned).

Custom Field Types and Validators

One area where declaring your fields is most advantageous is also perhaps the most repetitive type of code in Models: validation. Prior to Ext JS 5, the declaration of validation logic was uniquely a job for Ext.data.Model-derived classes. As such, these validations were not something other classes dealing with similar fields could reuse. At the same time, these validations were frequently related to the type of content in the field. For example, email addresses, phone numbers, gender, date of birth, etc.

With the introduction of custom field types, you can now reuse this logic across all your models. For example, we can declare a “gender” field type:

Ext.define('App.fields.Gender', {
        extend: 'Ext.data.field.String',
        alias: 'data.field.gender',
        validators: {
                type: 'inclusion',
                list: [ 'female', 'male' ]
        }
});

And then use it in any number of Models:

Ext.define('App.model.Person', {
        extend: 'Ext.data.Model',
 
        fields: [{
                name: 'name', type: 'string'
        },{
                name: 'gender', type: 'gender'
        }]
});

See this fiddle to experiment with the above example. In real-world applications, there are likely to be many opportunities to reuse field types and their validators.

Reference Fields and Associations

Declaring associations is another area in Ext JS 5 where we have reduced boilerplate code requirements. In previous releases, the hasMany, hasOne and belongsTo configs required that you manually maintain symmetric declarations on both “sides” of an association. This is no longer the case. You can declare an association in either of the associated classes (though typically on the “many” side).

For example, you can use hasMany on one Model and the corresponding belongsTo is no longer needed. Consider this set of declarations:

Ext.define('App.model.Base', {
        extend: 'Ext.data.Model',
        schema: {
                namespace: 'App.model'
        }
});
 
Ext.define('App.model.Person', {
        extend: 'App.model.Base',
 
        fields: [ 'name' ],
 
        hasMany: 'Order' // the "entityName" for "App.model.Order" (see below)
});
 
Ext.define('App.model.Order', {
        extend: 'App.model.Base',
 
        fields: [ 'name' ],
 
        hasMany: 'OrderItem'
});
 
Ext.define('App.model.OrderItem', {
        extend: 'App.model.Base',
 
        fields: [ 'name' ]
});

The above example takes advantage of two new features in Ext JS 5:

  • Declaration of associations on only one of the associated Models.
  • Automatically generated entityName values (by setting the Schema namespace). This allows you to have friendly names for your Models and their generated getter and setter methods while still following the recommended namespace structure in your application. Schema is also new to Ext JS 5 and has some other useful options worth looking into (such as its proxy config), but because there is typically not much need to directly interact with the schema, we won’t cover it further here.

The above example is, however, overly simplified from the perspective of true applications where these records are often linked to each other by holding id values in certain fields. For example, an OrderItem will often have an orderId field and the Order will likely have a personId field. These are sometimes called “foreign keys” and maintaining the integrity of these fields is critical.

When such fields are present, the new reference config can be used to indicate the type of Model a particular field references. Reworking the above code in this example:

Ext.define('App.model.Person', {
        extend: 'App.model.Base',
        fields: [ 'name' ]
});
 
Ext.define('App.model.Order', {
        extend: 'App.model.Base',
 
        fields: [{
                name: 'name',
                type: 'string'
        },{
                name: 'personId',
                reference: 'Person'
        }]
});
 
Ext.define('App.model.OrderItem', {
        extend: 'App.model.Base',
 
        fields: [{
                name: 'name',
                type: 'string'
        },{
                name: 'orderId',
                reference: 'Order'
        }]
});

Given the new reference configs shown here, the same associations are created as with the hasMany example. More than that, Ext JS 5 will maintain these fields as well. For example, adding an OrderItem to the orderItems association of an Order will automatically set the orderId field.

Many-to-Many Associations

In addition to streamlining associations using reference fields, we also added support in Ext JS 5 for a new type of association: many-to-many. A typical scenario where this comes up is modeling Users and Groups. A user can be a member of multiple groups, and a group can have multiple users. Let’s consider a simple declaration like this:

Ext.define('App.model.User', {
        extend: 'App.model.Base',
 
        fields: [ 'name' ],
 
        manyToMany: 'Group'
});
 
Ext.define('App.model.Group', {
        extend: 'App.model.Base',
 
        fields: [ 'name' ]
});

Notice again that only one Model has to declare the association (using the manyToMany config). This creates methods on each class similar to hasMany. In the above case, the User class gets a groups method and Group gets a users method. As with hasMany, these return stores that hold the associated records. Under the covers, however, careful bookkeeping has to take place to maintain this type of association.

When models store keys to each other, maintenance of their relationship is straightforward. In the case of many-to-many associations, however, it is not possible to represent the relationship as fields of either associated record. Further, adding a Group to the groups store for a User must add the User record to that Group’s users store (if it exists).

To see this in action, check out this example. One thing is quite new and different in this example:

var session = new Ext.data.Session();

We’ll see more on this later, but for now it is sufficient to say that the extra maintenance required for many-to-many associations is handled by this session instance. We’ll see later how we can use the session to look at the pending edits for these associations.

Connecting The Pieces

Now that we have our data model declared, we’re ready to see some new ways we can use it in our application. Using data binding in Ext JS 5, we can much more easily get our data presented to the user, but then the fun starts as soon as the user begins editing that data.

Form Validation

With the introduction of ViewModels, Ext JS 5 now has the ability to know the connection between the value of a form field and the underlying data storage. Data binding for form fields goes to the next logical step and also connects the validators from Model fields when you set the new config: modelValidation.

For example:

Ext.create({
        xtype: 'window',
        title: 'Validation',
        width: 350,
        layout: 'form',
        autoShow: true,
        viewModel: {
                data: {
                        person: new App.model.Person({
                                name: 'Bob',
                                gender: 'mal' // typo
                        })
                }
        },
        defaultType: 'textfield',
 
        modelValidation: true,
 
        items: [{
                fieldLabel: 'Name',
                bind: '{person.name}'
        },{
                fieldLabel: 'Gender',
                bind: '{person.gender}'
        }]
});

The above form is just a basic data binding form using a Person record in the ViewModel. By adding modelValidation: true, however, the child form fields automatically bind to the validator information for their value bindings. In this case, the gender field of the person record in the ViewModel is invalid and that is reflected by the Gender text field’s error indicator.

Data Sessions

The final piece of the puzzle then is to gather all of this validated data, so it can be saved to the server. In previous versions, this was done manually by tracking relevant records and stores and calling their save and sync methods. When dealing with multiple records and stores, this could become a complex process of bookkeeping, sequencing and callback chaining.

This is where Ext.data.Session can greatly simplify your code. The primary job of a session is to track records (by their type and id), so all related parties can retrieve a reference to the same record object. By tracking all of these records, the session ensures that the contents of associations are coherently updated and maintained as edits occur.

Creating a Session

Sessions are typically created using the session config. The key decision then is where in the view hierarchy to create a session. Creating a session at the top (or “viewport”) level makes sense if the application uses a relatively stable set of records over its lifetime. If this is not the case, a child view such as a modal window or closable tab would make more sense because the session can be destroyed along with the view that owned it.

Any component can retrieve the appropriate session instance by calling the lookupSession method. This method will consider that component’s session config, if specified, or find the session from the nearest ancestor in the view hierarchy that has a session configured. In other words, the “session” is inherited by child components.

Getting Records

Records can be manually fetched from a session by calling getRecord or created in the session by calling createRecord. These methods are seldom called directly when using ViewModels which automate this using the links config. Whether called directly or automated by ViewModels, these methods ensure the coherency of record instances tracked by the session.

When records are loaded by the session, traversing their associations will load associated records into the same session. This gives the session the ability to gather changes for all of these records when it comes time to save back to the server.

It is worth mentioning that all records loaded or created by a session are owned by that session and cannot be shared with another session.

Inspecting a Session

You can request that the session produce the current state of all its records by calling its getChanges or visitData methods. The information returned by these methods can be used for a variety of useful purposes such as:

  • Saving all changes to the server in a single transaction
  • Transfer the state of the client’s records to the server to enable custom Ajax requests
  • General diagnostics

Updating a Session

The opposite of getChanges is update. This method can be used to inject any number of record changes of any type (create, update, drop) using the same format returned by getChanges. Internally this mechanism is used to support child session (discussed below), but it enables other techniques as well:

  • Preload a session with all initially relevant records at page load time. This can eliminate many independent Ajax calls to load records and stores individually.
  • Transfer results of server-side record changes back to the client (perhaps in the response to a custom Ajax request) for subsequent saving (or discarding). That is to say, you can seamlessly transfer the current state of records from the client to a server-side method and merge the resulting record changes back on the client without having to commit those changes on the server at the same time. This can be helpful when building “what-if” user experiences.

Child Sessions

It is fairly common to present a user with some sort of user interface that allows them to make changes and then accept or reject those changes. For example, a typical “OK/Cancel” window. We can isolate such a window’s ViewModel by creating a new “child” session. This child session communicates with its parent session to retrieve record data but does not immediately modify those records. Instead, it creates records of its own to hold on to changes. When the user accepts the changes, we simply call the save method on the child session.

You can see this in action in the Kitchen Sink example.

Saving Sessions

When it finally comes time to save changes back to the server, we have a couple choices. We can use getChanges described above and send the data in a custom Ajax request. Or, we can use the standard proxy defined for each Model.

To use the standard proxy, we call getSaveBatch on the session. This returns an Ext.data.Batch object on which we call start. The individual operations in this batch are ordered in such a way as to ensure that the server is never presented with records that it is unprepared to handle. This ordering is derived from the Model’s reference fields. For example, since an OrderItem has an orderId field, any created Order records must be sent to the server first before OrderItems with that orderId.

If the server is handling id generation, this is also when the client-generated IDs are corrected and the corresponding reference fields on associated records are updated.

Caveats

For all their usefulness, sessions do have limitations. These stem from the fact that, to do its job, a session must retain references to all records attached to it and can only remove them when a record is dropped. If a session is over-used, it will become a large memory consumer. You must take care in choosing where to create sessions and allowing them to be decommissioned by connecting them to components with a finite lifecycle.

Conclusion

We think these improvements all across the data layer will make it easier to develop and maintain your applications, and even provide you with some techniques that were previously impossible. We’d love to hear how you’ve used these new features in your applications, and of course, if you have questions we’d be happy to assist you in the forums.

20140702-deep-dive.jpg 10 Comments   Read more