How to Build a Great Looking Universal App with Ext JS – Part 2

Posted on in Ext JS 6

In part 1 of this series, I described what a universal app is and how it’s created in Ext JS 6. Now, I’ll show you how I built my application.

Folder structure

To create a high performance Ext JS 6 universal app, I used Sencha Cmd. I generated a workspace first, because in my folder I host multiple versions of my app (free and commercial), which all share the same code packages and framework.

To generate a workspace, I browsed to the downloaded Ext JS 6 SDK. From there, I typed the following command:

sencha generate workspace ../spotifinderworkspace6

This generated the following structure:

Generate workspace

Then, I generated the application. I called it _engine. Why? Because I can create customized versions of my app with different behavior or branding. For example, a music app that plays songs in Pandora. To do that, I would only need to extend the engine Ext.Application, and override certain elements.

Here’s how I generated the application:

cd spotifinderworkspace6/ext
sencha generate app Engine ../_engine

Generate application

Toolkits

The classic folder is the folder structure for the classic toolkit. It contains the rich components that are great for desktops (or tablets). Also, it has support for legacy browsers.

Here’s what my app in the classic toolkit looks like:

App in Classic toolkit

It kind of looks like Spotify. I used traditional desktop components with a custom stylesheet. Because the application is shown on a large screen, there is a lot of space for showing extras, such as the album artwork, additional information, and also the settings screen (which is docked to the side).

I created unique views. Some of these views require their own logic. That’s why my folder structure in the classic toolkit looks like this:

Folder structure in Classic toolkit

The modern folder contains lightweight touch components. These are great for touch devices, including phones (or in some cases, tablets too). These components are optimized for a touch experience instead of mouse and keyboard. Because these components are lightweight, they also perform really well on a mobile device which has less processing power.

App in Modern toolkit

Because the screen is small, just the absolute necessary components are shown. To open the settings view, tap the gear button. It will nicely slide in the settings screen with an animation.

Folder structure is small

Because it doesn’t contain too many components, my folder structure is small. Again, only views and some behavior code, which are required by this view, are unique. Everything else will be shared across toolkits.

The shared code can be found in the app folder:

Shared code in app folder<

Tip: You can extend from view controllers (VC) too.

For example, you could have a shared Viewport VC that contains most of the behavior. The Viewport VC of the classic and modern toolkit folders only contains code that’s required for their own components.

Here’s an example. Below is a snippet of the Viewport VC, which is located in the app/main/ folder. As you can see, it extends from Ext.app.ViewController. The class itself is called Engine.view.main.MainController.

Snippet of Viewport VC

Now, here is the code of the Viewport VC in the classic folder. It’s located in the classic/src/main/ folder, and this time it extends from Engine.view.main.MainController, which is the shared VC. Don’t forget to put an alias in this class. That’s how you would link this classic view controller to the classic main view.

Code of Viewport VC in Classic folder

Microloader

The microloader can detect on which environment it’s running, and serve the right experience. This means when I load my application on a desktop, I see my desktop version of the app with the Spotify theme, and when I open my application on an iPhone, I get the phone interface with the iOS theme.

All the magic here is in the Ext.platformTags. You can even run this command from your browser console, in an existing Ext JS 6 app. It will provide the object with all kinds of information, such as the browser version you’re running, OS, device type, etc tamiflu dosage for adults.

You can configure your app, so it serves the right experience. The secret here is the app.json file. You need to create build profiles, and you can bind every app.json setting you like to a build profile, such as the toolkit (component set) and the theme:

    "builds": {
        "classic": { //name of the build profile
            "toolkit": "classic", //component set
            "theme": "theme-spotifext", //name of the theme
        },
        "modern": {
            "toolkit": "modern",
            "theme": "theme-cupertino",
        }
}

Switching the experiences is handled in the index.html file. When you generate your application with Sencha Cmd, this will be all stubbed out for you.

Index.html file

MVVM Pattern

With Ext JS 6, you can use the MVVM pattern.

MVVM pattern

View – all components on your screen
ViewController – logics for a view
ViewModel – for binding data to a view

data model – structure of your entity
data record – the actual data
data store – client-side cache

All views in Ext JS can be nested, and so can the view models and view controllers.

Nested views, view models, and view controllers

The benefits of this pattern is that code is easy to read and maintain.
It’s a consistent file structure for your code and classes, and it facilitates code reuse.

Why Ext JS vs. Open Source

With Ext JS 6, you get an all-in-one solution. You don’t need to maintain various dependencies and have expertise in many different technologies that all need to work together.

For the application that I created, I used the following Ext JS 6 solutions.

Ext JS 6

Example Open Source Solution

Sencha Class System ECMAScript 6 Classes
Border Layout JS + CSS
MVVM Architecture Angular JS
Desktop App Bootstrap / Responsive CSS
Mobile App jQuery Mobile / Ionic
Promises ECMAScript 6
Grids jQuery Plugin
Touch Gestures / Events JS
Routing AngularJS Plugin
Offline Caching HTML5 / JS
Theming Sass / CSS
Sencha Cmd Grunt + Yeoman + Bower

I could have used an open source solution, but then I would have had to stack technologies on top of one another. For example, ECMAScript 6 is not supported by Internet Explorer yet. With Bootstrap or responsive web design, my users would have to download lots of code, which they don’t even see, and it’s not optimized for each device (as described in my previous blog post). There are jQuery plugins for grid components, but these are not half as powerful, and don’t perform well with large data sets. And who should I call when my AngularJS plugin suddenly stops working with the latest browser update?

My application is just a simple app, and I already would have at least 10 dependencies. What about a real enterprise app, which has a codebase that’s 50 times bigger? I would need to have knowledge of all these various tools, cross my fingers that these technologies work well together, and are future proof for the next 5 or 10 years (while browsers are upgrading).

Conclusion

That’s exactly the reason why I chose Ext JS 6. An all-in-one solution, where everything is configured the same way, every piece works together, and looks the same. And because Sencha is a commercial company, there is always a support number to call, and they will make sure that my app works in the future.

How to Build a Great Looking Universal App with Ext JS – Part 1

Posted on in Ext JS 6

Background

Back in 2011, I wanted to create an app. I love music, and I am a huge fan of Spotify. I love that I can listen to a huge database of songs. The only thing that always bothered me was that I had to manually search for songs. That’s fine when I’m using my laptop, but it’s not so great when I’m walking or biking, and I use Spotify on my phone. Typing on a virtual keyboard is just not fun.

So, I created a Sencha Touch app that could connect to my LastFm account (an online database that can “scrobble” and save music that you’ve listened to). My app lists all the music I like, and with one button tap, I can play the song in Spotify.

Sencha Touch app

Sencha Touch was great for building this app. It has a powerful, smooth scrolling list and stylesheets that make my app look great on my iPhone. It was quick to build and ready to use.

I liked this app so much that I decided to share it. I deployed my app in the Apple App Store, by wrapping it with Cordova. Then, I noticed I was also using it on my desktop. It was just easier to choose songs, so I deployed my app on my webserver and hosted it in the Google Chrome Web Store.

A week later, I checked my reviews on the Chrome Web Store. I was heartbroken to see that I only had bad reviews: “What a weird looking app” and “Why can’t I use the mouse wheel to scroll?” It totally made sense though – my app was originally designed for iPhones. It looked like an iPhone app because of the stylesheet, but it behaved like a touch app because it was built with Sencha Touch using Touch events & gestures. To scroll the music list, users had to tap the list and drag it up or down. That works great on touch devices, but it’s odd on a desktop. I realized that I needed a desktop version of my app too.

Ext JS app

That was when I started to play around with Ext JS, which is a great framework for creating desktop applications. It has fast performing desktop components like the grid, and a similar MVC architecture and class system as in Sencha Touch 2. I created the desktop version, and later I migrated my Ext JS 4 app to Ext JS 5. I chose Ext JS 5 because I wanted to clean up my code and use the new MVVM pattern, and also use touch events, responsive design, and stylesheets for a tablet version of my app. But when I realized I had to maintain two different code bases, with two frameworks, I turned to Ext JS 6.

Now, with Ext JS 6, you can create universal apps. With one codebase, your apps run on any supported device type.

Tech Specs of My App

Before we move on, here are some technical specs for how my app works.

  • To play songs in Spotify, I use URL Schemes.
  • To retrieve data from LastFm, I use an external JavaScript API, that must be in a custom written proxy, which is part of a package.
  • The LastFm username is saved in the HTML5 browser local storage.
  • Phones will get modern touch components, for now just iOS views.
  • Tablets and desktops will get rich classic desktop components, with a Spotify look & feel.
  • MVVM pattern is used.

Universal Apps vs Responsive Web Design

There are differences in how Universal Apps work in Sencha frameworks, and how Responsive Web Design is used for mobile websites to respond to certain environments.

Responsive Design for websites is usually done within a stylesheet using relative units, values in percentages, and breakpoints (mediaqueries) that can re-order and show/hide certain HTML elements.

Take a look at the code snippet below:

@media all and (min-width: 800px) and (max-width: 1024px) {
 ul li.products {
    width: 50%;
    display: inline-block;
 }
}
@media all and (min-width: 1025px) {
 ul li.products {
    width: 25%;
display: inline-block;
 }
}
@media all and (max-width: 799px){
 ul li.products {
    display: none;
 }
}

The previous code example has a few breakpoints. Small screens with a viewport width smaller than 799px, screens between 800px and 1024px, and large viewports with screens wider than 1025px. On big screens, there are list elements positions next to each other with a size of 25% width. For medium screens it’s 50%, and for small screens (such as phones), the list will be hidden.

This technique is great for websites, but not for real world applications. Why?

  • When you are on a mobile phone, chances are that you are on a slow mobile network or using an (expensive) data plan. That’s very expensive, and you’re not even seeing these elements and data.
  • Also, you may want to change the text on a smaller screen size. I’ve worked a lot with copywriters, and they believe that text on a phone should be written differently than what’s on a desktop. Nobody likes to read whole books of text on a small screen.
  • By using only responsive web design, you’re probably missing a lot of opportunities to refine content or use device features, because you’re serving one code base. For example, your fancy floating calendar component looks great on a desktop, but it doesn’t work well on a phone. A text hyperlink works fine when you control your app with a mouse, but you will probably have trouble tapping it on a small touch device. Users are used to native app behavior, such as the built-in datepicker on an iPhone, or a big button as a link. Most often, responsive mobile websites don’t deliver the same experience as a native app.

That’s why the Sencha approach is different and better. Universal apps in Ext JS 6 are far beyond just responsive design. We know you want to control the UI with more than just re-ordering, show/hiding elements. There are various approaches that you can take, and most of these, are not just limited to views. You can also control data and behavior.

Toolkit / Universal app approach: The user experience is chosen before the framework is downloaded.

How it works: You can create different views with touch (modern toolkit) or desktop (classic toolkit) component sets tamiflu generic. The microloader will detect your device, OS, or browser, and serve the right component set for you, by loading a build profile. You can attach a particular theme to that build profile. You can create as many build profiles as you like, and it’s not only limited to views, you can also serve different data stores or behavior code.

In the screenshot below, you can see how my application looks on a desktop, and how it looks on an iPhone:

App UI on desktop and phone

Device specific stylesheets: The stylesheet is chosen before the framework is downloaded.

How it works: Ext JS 6 ships with themes (Sass stylesheets) that are great for classic toolkit, touch interfaces (with the look and feel of iOS, Android, and Windows Phone), or stylesheets that look great on both toolkits. The microloader can detect the environment, and serve the correct theme.

Device specific stylesheets

Device Profiles: The profile for each user is chosen when the application launches.

How it works: It’s possible to create a device profile, which contains different code or different component positioning. For example, when you open an email app on your phone, you see a list with an overview of all emails, and when you tap on an item, it opens the email on top. However, when you open the email application on a tablet, the list is docked to the left, and the body of the email is positioned on the right side of the screen. You can achieve these layouts with device profiles. It’s not just re-positioning certain components (list docked or not). It’s also different behavior under the hood (when you tap an email, it opens an extra window on top vs. loading next to the list).

Device profiles

Responsive Design with JavaScript: Code responds to custom criteria at runtime.

How it works: JavaScript responds to certain conditions (like screen size) at runtime. It’s possible to create any custom condition and have the view, data, or behavior respond.

Responsive Design with JavaScript

Traditional Web Design with CSS: The view responds to an environment at runtime.

How it works: You can also use traditional responsive web design. You can use it for styling simple elements in views.

Conclusion

In this article, I’ve described what an Ext JS 6 universal app is, what I like about the universal app approach, and why I converted my app. In Part 2, I’ll show you exactly how I converted my music app to a universal app.

I like to build a mobile application what Sencha framework should I use?

Posted on in Ext JS 5 & 6 Questions

With Ext JS 6, you will be able to build a mobile application. Ext JS 6 is a JavaScript framework based on HTML5 for building cross-platform mobile web applications targeting desktop, tablets, and smartphones.

To build a mobile application, you could make use of the Ext JS 6 modern toolkit. This toolkit contains components which are similar to native touch controls. Sencha delivers Stylesheets for iOS, Windows Phone and Android (Material Design), to make your application look like a native app.

You can download our trial version of the framework from here:

https://www.sencha.com/products/extjs/evaluate/

And here are some handy getting started materials:

  • http://docs.sencha.com/extjs/6.2.0-modern/
  • http://examples.sencha.com/extjs/6.2.0-ea/examples/kitchensink/?profile=material
  • http://examples.sencha.com/extjs/6.0.0/examples/kitchensink/?profile=cupertino
  • http://se.sencha.com/getting-started/
  • https://www.sencha.com/blog/how-to-upgrade-a-sencha-touch-app-to-ext-js-6-modern-toolkit-part-1/
  • https://www.sencha.com/blog/how-to-build-a-great-looking-universal-app-with-ext-js-part-1/

Make your mobile webapp work offline with application cache

Posted on in Mobile

This tutorial will help you to put your mobile webapp offline.

1. create your cache manifest file
create a file yourappname.manifest in your application root.
In the file enter all files you have to cache to make your app working offline.

For example the app.manifest file looks like this:

CACHE MANIFEST
#rev2

# Explicitly cached entries
CACHE:
index.html

img/icon.png
img/phone_startup.png
img/tablet_startup.png
img/main-image.png

css/ext-touch.css
css/default.css

js/ext-touch-debug.js
js/ext-touch.js
js/index.js

# Resources that require the user to be online.
NETWORK:
js/twitter.js

#If source in inaccessible serve other file. for example: /index.php /index.html
FALLBACK:

2. Add your manifest to your application .html file header
In your html file:



3. Create a .htaccess file and add expire configuration for your *.manifest file to your app root.


ExpiresActive On
ExpiresDefault "access"

4. Add type manifest to your apache config (apache.conf / vhost.conf or .htaccess file)

AddType text/cache-manifest .manifest

That's it, now your app should work offline. You should know that, as soon as the manifest file fails with caching the files. It stops. That means that the files will not be updated.

Use this code to check/swap cache via code:

var i = -1;

// Convenience array of status values
var cacheStatusValues = [];
cacheStatusValues[0] = 'uncached';
cacheStatusValues[1] = 'idle';
cacheStatusValues[2] = 'checking';
cacheStatusValues[3] = 'downloading';
cacheStatusValues[4] = 'updateready';
cacheStatusValues[5] = 'obsolete';

// Listeners for all possible events
var cache = window.applicationCache;
cache.addEventListener('cached', logEvent, false);
cache.addEventListener('checking', logEvent, false);
cache.addEventListener('downloading', logEvent, false);
cache.addEventListener('error', logEvent, false);
cache.addEventListener('noupdate', logEvent, false);
cache.addEventListener('obsolete', logEvent, false);
cache.addEventListener('progress', logEvent, false);
cache.addEventListener('updateready', logEvent, false);

// Log every event to the console
function logEvent(e) {
i=i+1;
var online, status, type, message;
online = (isOnline()) ? 'yes' : 'no';
status = cacheStatusValues[cache.status];
type = e.type;
message = 'online: ' + online;
message+= ', event: ' + type;
message+= ', status: ' + status;
if (type == 'error' && navigator.onLine) {
message+= ' There was an unknown error, check your Cache Manifest.';
}
log(i + ' ' + message);
}

function log(s) {
//alert(s);
console.log(s);
}

function isOnline() {
return navigator.onLine;
}

if (!$('html').attr('manifest')) {
log('No Cache Manifest listed on the tag.')
}

// Swap in newly download files when update is ready
cache.addEventListener('updateready', function(e){
// Don't perform "swap" if this is the first cache
if (cacheStatusValues[cache.status] != 'idle') {
cache.swapCache();
log('Swapped/updated the Cache Manifest.');
}
}
, false);

// These two functions check for updates to the manifest file
function checkForUpdates(){
cache.update();
}
function autoCheckForUpdates(){
setInterval(function(){cache.update()}, 10000);
}

More info's, can be found here:
http://developer.apple.com/library/safari/#documentation/iPhone/Conceptual/SafariJSDatabaseGuide/OfflineApplicationCache/OfflineApplicationCache.html