How to Upgrade a Sencha Touch App to Ext JS 6 Modern Toolkit – Part 2

Posted on in Ext JS 6 Sencha Touch

Cupertino Theme

In part 1 of this blog post series, I discussed the changes in Ext JS 6 Modern Toolkit and showed you how to do a basic mobile upgrade of your Sencha Touch app. In this article, I’ll show you how to do an advanced mobile upgrade.

Advanced Mobile Upgrade

For the advanced mobile upgrade, you will use the MVVM pattern. It will take more time and steps to upgrade this way, but you will have a lot of advantages with the latest framework and all of the new features and classes. Also, you can improve your application performance and code base with the new MVVM architecture.

I’ve cloned this dinmu1 folder to a new folder called dinmu2, so you can see the differences.

Start with Migrating the Views

  1. In the app/view folder, create the following folder structure (every view gets its own subfolder):
    1. app/view/main
    2. app/view/settings
  2. Move Main.js inside the main subfolder, and SettingsView.js into settings subfolder. (I also renamed SettingsView.js to Settings.js)
  3. Edit the namespaces for these two views to:
    1. Dinmu.view.main.Main
    2. Dinmu.view.settings.Setting
  4. At this point, you broke the app because the viewport can’t find Main.js and the Main.js view can’t find the Settings view, so you have to fix this:
    1. In the app.js, you can remove the line:
      Ext.Viewport.add(Ext.create('Dinmu.view.Main'));
    2. Above the launch() method, you create a new viewport, via the new way Ext 6 provides, by setting the mainView property to: mainView: 'Dinmu.view.main.Main',
    3. Remove the views: ['main'] from app.js
    4. Add 'Dinmu.view.main.Main' to the requires array
    5. In Main.js, change the requires for the Settings View to 'Dinmu.view.settings.Settings'
  5. To confirm that nothing breaks after this fix, you can run a sencha app refresh, and you shouldn’t see any errors.

    Files

Migrate the Controllers to View Controllers

  1. Create the following new file:
    app/view/main/MainController.js
  2. Create the following class definition:

    Ext.define('Dinmu.view.main.MainController', {
        extend: 'Ext.app.ViewController',
        alias: 'controller.main',
     
        //all the VC methods
        init: function(){
          console.log("new VC is initialized");
        }
     
    });
  3. Wire up the view controller to the main view:
    In Main.js, add the following line: controller: 'main',
  4. Also add the MainController to the requires array: Dinmu.view.main.MainController
  5. Run another sencha app refresh, and test the app in the browser. You should see a log message that states the wiring of the VC was successful. Note, you don’t need to wire this controller up to the Settings view. Because Settings view is nested inside the main view, it can always access the main controller.
  6. You can remove the controllers array from app.js, because you won’t use it anymore.
  7. Remove the init method from the view controller and copy over all the methods from app/controller/Main.js into the new view controller.
  8. Now comes the tricky part. You won’t use the refs and control blocks, so you need to fix these. Instead of the control block, you will create listeners in the view.

    There are 5 controls that need to be replaced:

    • onCarouselChange – activeitemchange in the main view
    • btnBack – tap back button in title bar
    • onSettingsBtnTap – tap settings button in settings view
    • onToggle – toggle on togglebutton
    • onRefresh – executed on tap of the refresh button

    In the Main.js view class, you will create the activeitem change listener:

    listeners: {
       'activeitemchange': 'onCarouselChange'
    },

    On the back button in Main.js, you will create a tap listener:

    listeners: {
       'tap': 'onBackBtnTap'
    },

    On the settings button in Main.js, you will create a tap listener:

    listeners: {
       'tap': 'onSettingsBtnTap'
    },

    On the toggle button in Settings.js, you will create a toggle listener:

    listeners: {
       'change': 'onToggle'
    },

    On the refresh button in Settings.js, you will create a tap listener:

    listeners: {
       'tap': 'onRefresh'
    },
  9. When you run the application in your browser, you will notice various event errors. The references with component queries are broken. You will fix these now.
  10. All the references to this.getMainView() can be replaced for this.getView(). Because the view controller now knows about the view, you can fix this one easily. I replaced it on 3 places.

    The other view references that you need will get a reference on the component, that you can look up later. In Settings.js, add the following property: reference: 'settings'.

    In the MainController, replace this.getSettingsView() with this.lookupReference('settings').

    You can fix the onToggle Method like this:

    var s = this.lookupReference('settings');
     
    if (!newVal) {
       s.down('field[name="city"]').enable();
       s.down('field[name="country"]').enable();
       s.down('field[name="units"]').enable();
    } else {
       s.down('field[name="city"]').disable();
       s.down('field[name="country"]').disable();
       s.down('field[name="units"]').disable();
       s.down('field[name="city"]').reset();
       s.down('field[name="country"]').reset();
    }

    In the Main.js view, put a reference in the titlebar configuration:

    reference: 'titlebar',

    Then replace the onCarouselChange method with:

    onCarouselChange: function(carousel, newVal, oldVal) {
       var t = this.lookupReference('titlebar');
     
       if (newVal.getItemId() == "mainview") {
          t.down('button[action=back]').hide();
          t.down('button[action=settings]').show();
          t.setTitle('Do I need my Umbrella?');
       } else {
          t.down('button[action=back]').show();
          t.down('button[action=settings]').hide();
          t.setTitle('Settings');
       }
    },

  11. Change the onLaunch method to init. Note, this will break the application because Dinmu.utils.Functions.loadData(), uses the Settings store, which is not wired up to a controller anymore. For now, comment the line with Dinmu.utils.Functions.loadData() out.
  12. Run another sencha app refresh and test the app in the browser. Everything except the refresh button should work. The refresh button requires the store, which is not linked yet.

Link the Store to a View Model

  1. Create the following new file:
    app/view/main/MainModel.js
  2. Create the following class definition:

    Ext.define('Dinmu.view.main.MainModel', {
        extend: 'Ext.app.ViewModel',
     
        alias: 'viewmodel.main',
     
        requires: [
     
        ],
     
        stores: {
     
        }
    });
    
  3. Wire up the view model to the the main view:
    In Main.js, add the following line: viewModel: 'main',
    Don’t forget to put the Dinmu.view.main.MainModel into the requires array.
  4. Now, link the Settings store; first add Dinmu.store.Settings to the requires array.
  5. In the Settings store, set an alias: 'store.settings' in the store class definition.
  6. In Ext JS 6, Stores don’t automatically set the storeId to the name of the class, therefore set the storeId to Settings, so the store manager can find the store via Ext.getStore('Settings')
  7. After that, add the following store to the stores object, (the type points to the settings alias):
  8. 'settings': {
       type: 'settings'
    },
  9. Enable the Dinmu.utils.Functions.loadData() line, which you commented out before in the MainController. Then run another sencha app refresh and test your app.
  10. At this point, you should have a working app that uses the MVVM pattern.

Other App Improvements

  • This application doesn’t use data feeds in the store. However, another big advantage with Ext JS 6 is that you don’t need to code all the model fields in your Model definition. It gets the data directly from the feed. That saves you from typing all the data in the feed, and makes your model definitions a lot smaller.
  • Another thing that’s different in Ext JS 6 is the config blocks. In Sencha Touch, you defined everything in the config block; in Ext JS 6, you only put properties in a config block that need the auto generation of getters, setters, apply, and update methods. For the Dinmu application this means that I had to remove most of the config blocks. For most of the classes, the config block in Sencha Touch style works fine, but you could run into weird problems at some point, if you leave them.
  • Promises and Deferreds support. I was always a bit amazed that the way I coded the saving of the settings form just worked. There’s a lot of magic going on in the sync() method, and the way they order the new created records, removed and edited records. It would have been a lot better, if I could have coded it this way:
    • Enter the form.
    • Check if localstorage contained old settings.
    • Remove old records, if any.
    • Sync store, and after the sync is complete, add new records.
    • Sync store, and after adding, load what’s in the store.

With Ext JS 6, you can do this because it supports promises and deferreds, which allows you to chain methods, via the then() method. Look at how I coded the removeAllSettings and addSettings methods. In the onRefresh method, I chained it. You can compare it with the dinmu1 or touchdinmu files to see how this code differs.

Upgrade the Theme

  1. You can switch themes by changing the theme property in the app.json file. Out of the box, you can choose between the following themes:
    • theme-cupertino (ios theme)
    • theme-mountainview (android theme)
    • theme-blackberry (blackberry theme)
    • theme-windows (windows theme)
    • theme-neptune
    • theme-triton (default)
    Cupertino Theme
    Triton Theme

    After switching the theme, you will need to run sencha app build.

  2. The platform switcher in Ext JS is renewed. Instead, you will now use the profiles build block in app.json. To set this up, write in app.json:
  3. "builds": {
      "ios": {
        "toolkit": "modern",
         "theme": "theme-cupertino"
      },
    
      "android": {
        "toolkit": "modern",
          "theme": "theme-mountainview"
      },
    
      "windows": {
        "toolkit": "modern",
        "theme": "theme-windows"
      },
    
      "bb": {
        "toolkit": "modern",
        "theme": "theme-blackberry"
      },
    
      "default": {
        "toolkit": "modern",
        "theme": "theme-triton"
      }
    },

    To enable the multiple themes on your development machine, add these lines to the app.json bootstrap block:

    "bootstrap": {
      "base": "${app.dir}",
     
      "microloader": "bootstrap.js",
      "css": "bootstrap.css",
     
      "manifest": "${build.id}.json" //this is the magic, which generates a manifest file, to load on local.
    },

    To enable the multiple themes on your production build, add these lines to the app.json output block:

    "output": {
       "base": "${workspace.build.dir}/${build.environment}/${app.name}",
       "appCache": {
          "enable": false
       },
       "manifest": "${build.id}.json",
       "js": "${build.id}/app.js",
       "resources": {
         "path": "${build.id}/resources",
         "shared": "resources"
        }
    },

    In index.html you write:

    Ext.beforeLoad = function (tags) {
        var s = location.search,  // the query string (ex "?foo=1&bar")
            profile;
    
        if (s.match(/\bios\b/) || tags.ios !==0) {
            profile = 'ios';
        }
        else if (s.match(/\bandroid\b/) || tags.android !==0) {
            profile = 'android';
        }
        else if (s.match(/\bwindows\b/) || tags.windows !==0) {
            profile = 'windows';
        }
        else if (s.match(/\bbb\b/) || tags.bb !==0 ) {
            profile = 'bb';
        }
        else {
            profile = 'default';
        }
    
        Ext.manifest = profile; // this name must match a build profile name
    };
    

    You will need to run sencha app refresh and sencha app build, which builds all profiles, to get it up and running.

  4. Themes for Ext JS 6 Modern toolkit use the same packages structure as Ext JS did. This is great, because it means that you can extend from your own theme packages, and you can generate custom themes with Sencha Cmd:
  5. sencha generate theme theme-MyTheme

Even if you don’t plan to create custom theme packages, theming is more advanced. To upgrade an existing theme, you have to put all the variables in the sass/var/ folder.

Take a look at my sass/var/all.scss which I used for the weather app application. The custom Sass / CSS classes will be stored in the sass/src/ folder. For an application (without custom theme packages), you have to map the folder structure of your JS applications. In other words, app/view/main/Main.js has a Sass file in this location: sass/src/view/main/Main.scss.

Mountainview Theme

I could take most of my styling directly from my Sencha Touch application. However, there is no “default” Sencha Touch theme anymore, instead there’s the Neptune & Triton themes, which both have different Sass variables and require different DOM.

This means that when you used custom styling for templates (tpls) etc, it won’t break in your upgraded app, but when you used custom Sass to override the Sencha Touch theme, you might see differences. The best practice is to manually go through all the views in your browser, and check to see if the styling is correct. Take a look at my sass/src/view/main/Main.scss which I used for the weather app application.

In the next article in this series, I will show you how to do an advanced universal upgrade.

How to Upgrade a Sencha Touch App to Ext JS 6 Modern Toolkit – Part 1

Posted on in Ext JS 6 Sencha Touch
Cupertino Theme

Previously, I wrote a blog post on how to create great looking universal apps with Ext JS.
However, we also have lots of customers who currently have a mobile (phone or tablet) application and want to upgrade it to Ext JS 6.

In this tutorial, I will show you how you can upgrade your app, and why you should consider taking this step.

I used my existing tutorial files, “Do I need my umbrella” weather application, which I wrote a couple of years ago with Sencha Touch 2. You can find the original tutorial here. You can download the tutorial files here.

You don’t have to use these tutorial files, you can also just read through this guide and try it out with your own existing Sencha Touch 2 app.

Ext JS 6 Modern Toolkit and Sencha Touch

Ext JS has more (advanced) classes and features than Sencha Touch. You can create advanced enterprise desktop applications, and now you can also create advanced mobile applications or even advanced cross-platform apps.

We incorporated concepts from Sencha Touch 2, and merged them as “the modern toolkit” in Ext JS 5, with the modern core (class system, mvvm pattern, etc.), and there are also many updated classes. From a theming perspective, Ext JS 6 modern toolkit has been updated and looks different than Sencha Touch.

When you’re looking for an enterprise solution to create mobile apps, whether it’s a universal app or just mobile, there are many reasons why you’d choose Ext JS 6 Modern toolkit. I will explain these benefits to you in this article.

Then, I will take an example Sencha Touch 2 application, and migrate it to Ext JS 6 with the Ext JS 6 Modern toolkit.

What’s Different in Ext JS 6 Modern Toolkit

Here’s an overview of new features in Ext JS 6 compared to Sencha Touch.

Basic Upgrade

(No change to the MVVM pattern)

This upgrade allows you to use:

  • the latest mobile framework version, and support for the latest OS & browser versions
  • running your mobile application on your desktop computer too
  • controlling lists with your mouse scroll and keyboards (besides touch support)
  • new packages / theme packages structure
  • new Neptune and Triton (universal) themes
  • fast theme compilation with Fashion
  • cleaning up your models, by writing less code
  • JavaScript promises, for asynchronous code
  • out-of-the-box font-awesome integration
  • one of the new components/classes:
    • data grid
    • data tree
    • navigation tree list
    • soap, amf0, amf3 proxies
    • new charts
    • form placeholders

Advanced Upgrade

(Change to MVVM architecture pattern)

This upgrade allows you to use:

  • ViewControllers and ViewModels
    • The Stores and Controllers in MVC are global. VCs and VMs live together with a particular view, which means that they will be created with a view, and can be destroyed. ViewModels and ViewControllers therefore can improve your application performance. They also allow you to write less code and make it easier to maintain.
  • Databinding
    • Bind to data or component states. It allows you to do advanced things by writing less code.

Universal Upgrade

This upgrade allows you to:

  • Create cross-platform apps, for mobile phones and tablets, but also desktop computers. By supporting the modern (lightweight component set) and the classic rich desktop component set.
  • Support legacy browsers, like Internet Explorer 8, as well as the latest modern (mobile) browsers.

Things That Changed in the API

You can read a complete list of Ext JS 6 API changes here. The ones that I faced when upgrading the weather utility app are:

  • ViewControllers and ViewModels
    • The Stores and Controllers in MVC are global. VCs and VMs live together with a particular view, which means that they will be created with a view, and can be destroyed. ViewModels and ViewControllers therefore can improve your application performance. They also allow you to write less code and make it easier to maintain.
    • Sencha Touch has Ext.app.Controller.launch() methods; in Ext 6 Modern toolkit, it’s Ext.app.Controller.onLaunch()
    • In Sencha Touch, you had to define everything in a config block; in Ext 6 Modern toolkit, you just put properties in config blocks that need the magic methods (get, set, apply, and update). Although you don’t have to, you can clean up the config blocks.
    • There are changes in the way you wire up stores that you can read about in these docs:
    • Sencha Touch validations are now called validators
    • The Sencha Touch default theme was replaced by Ext JS 6 Modern toolkit themes – Neptune and Triton.
    • The default icon set that is being used is Font Awesome, instead of Pictos.

    Basic Mobile Upgrade

    For the basic, easy upgrade, we will stick with the existing MVC pattern. You will see that it won’t take many steps. However, you won’t be taking advantage of Ext JS 6. You will have the latest framework, with all its features and classes, but you won’t be using the new MVVM pattern.

    1.  Download the Ext JS 6 (trial version).

    2.  Look in your Sencha Touch project (app.js for example), and note the namespace that was used. For example, for the Weather Application, the namespace is “Dinmu”.

    3.  Generate an Ext JS 6 modern app:

    Navigate to the ext framework folder, and generate a project with:
    sencha generate app -modern
    For example:
    ext> sencha generate app -modern Dinmu ../dinmu1

    See https://github.com/savelee/ext-weatherapp/tree/master/dinmu1

    4.  Go to the project in your browser, you should see the new Ext JS 6 demo app.

    5.  In your file system, rename the <myproject>/app folder to something else (like app-backup)

    6.  Do the same for the app.js file; rename it to app-backup.js

    7.  Then, copy the app folder and the app.js from your Sencha Touch project, and paste it in your new Ext JS 6 project.

    In case you are loading external JS or CSS files via app.json, you can manually merge those lines into the new app.json. My advice is to do these kind of steps at the end, after you have your app running.

    8.  Run the following command from the command-line:

    1. sencha app refresh
    2. You might run into build errors here, because of API changes. For the Dinmu app, there was an error because Ext.device.Geolocation has been deprecated.
    3. When you have lots of custom components, you may run into problems here. The best way to solve them is to read the messages from the CLI, and open the Modern toolkit API docs to search for the classes that fail. In my case, it was the geolocation class that failed. In the docs, I noticed that there are no device APIs anymore. In Sencha Touch, these classes where wrappers for PhoneGap/Cordova support, that would fall back to the HTML5 API feature, if available in the browser. There is Ext.util.Geolocation, so I changed the code to use it. After I changed the line, I ran another sencha app refresh again, to check for more errors. See the results here.

    9.  When you don’t have any more errors anymore, you can try to run the application in the browser. When I ran my app, I got a console error in my app.js launch method.
    Ext.fly(‘appLoadingIndicator’).destroy();

    Basically, this is an error that tells you that you can’t destroy the “appLoadingIndicator” element, just because it’s not there. The index.html is just different. Now you don’t want to replace the index.html file, with the Sencha Touch one, because the calls to the microloader are different. It’s up to you, if you want to remove this destroy line in the app.js launch method, or if you take over the <style> and <body> tags from the Sencha Touch app. I liked the Sencha Touch simple CSS preloader, that you will see before loading any JS or CSS, so that’s why I took over those tags. After fixing this problem, I was able to open my Ext JS 6 app in the browser.

    10.  The application is running a bit odd. By inspecting my application, I noticed that in my Sencha Touch application I have controllers with launch methods. And launch methods on controllers don’t exist in Ext JS 6, instead they’re called: onLaunch. So I renamed it, and ran the application again.

    11.  This time I had a problem with the store. The store manager couldn’t find Ext.getStore('Settings'), because it was wired up to the controller like this: Dinmu.store.Settings. Instead, the store manager has to access it via the full class name. I fixed it in the controller, instead of wiring up the full path, and I just passed in the Store name.

    12.  The settings button was not visible; this was due the changes in the icon sets. I used the default font-awesome settings icon, and changed the iconCIs in the Settings button in Main.js to: x-fa fa-cog

    Settings

    13.  Last step was to run a build to make sure that I was able to build my application. I expected it to work, because the sencha app refresh command did not fail.

    And that’s it. After this last step, I was able to run the Weather Application as a full working Ext JS 6 mobile app.

    Coming Up Next

    In the next article in this series, I’ll show you how to do the advanced upgrade, where we will switch to the new MVVM pattern, and we can also clean up some code.