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

How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6

March 30, 2016 183 Views
Show

Ext JS is a mature framework. We’ve added a tremendous number of powerful new features and capabilities since the first release in 2007. Thousands of applications have been written using different versions of the framework. And some of these successful projects are still using Ext JS 3.4.

Some developers want to migrate their projects to the latest version so they can take advantage of new features, but they are unsure how to do so. Many of them give the same reasons for not migrating. They have a stable application, all bugs are fixed, and everything works properly because they chose one of the Best Javascript Libraries. At the same time, because the application is complex and contains numerous custom components and extensions, they believe the migration will be difficult.

On the other hand, almost all of them name the same advantages of upgrading to Ext JS 6:

  • Don’t have to control all browser updates.
  • Reduce time and effort of maintaining their application.
  • Improve performance and memory usage.
  • Take advantage of support for mobile devices and touch events.
  • Access to new Ext JS features and functionality that can be added
    with a couple of lines of code.

We always recommend that our customers migrate their applications to the most recent version of the framework – Ext JS 6.

In this article, I will show you a simple example of migration. As proof of concept, I have an Ext JS 3.4 grid example, and I migrated it to Ext JS 6. You can review the source code of the original and final applications.

The original example:
How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6

The final application:
How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6

We will build our new Ext JS 6 application based on the MVVM (Model-View-ViewModel) architectural pattern. MVVM provides an abstraction of a View (the ViewModel) that manages the changes between a Model‘s data and the View‘s representation of that data (i.e. data bindings). Read more about MVVM pattern.

How can I Generate a new empty Ext JS 6 project?

We can generate an empty Ext JS 6 project using the command line tool Sencha Cmd. Just navigate to Ext JS 6 SDK folder with your command-line or terminal, and run the following command:

sencha generate app -classic -starter=false Migration ../migration

You can read more about Sencha Cmd features.

Initialize a new project

We need to add Application and Main View classes to our empty project. These classes are necessary to run our application.

    1. We can generate the Main view using Sencha Cmd as well. Go to a newly created migration folder and run this command:
sencha generate view main.Main
    1. We will generate the Application class manually. Create a file app/Application.js with this content:
Ext.define('Migration.Application', {
    extend: 'Ext.app.Application',
    name: 'Migration'
});
    1. The last step is building our Ext JS 6 application and running it using an internal web server. Run the following commands from migration folder:
sencha app build
sencha web start
  1. Navigate to http://localhost:1841/ with your browser to check that the application is running. You should see the following screen:

How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6

How can I Migrate the Model?

Now we can start the actual migration of our Ext JS 3.4 code into our new Ext JS 6 project. The first step here is to migrate the Model. The Model describes a format for the data being used in the application. In Ext JS 3.4, the data format should be defined inside of a store definition using the fields property.

var store = new Ext.data.ArrayStore({
    fields: [
        {name: 'company'},
        {name: 'price',      type: 'float'},
        {name: 'change',     type: 'float'},
        {name: 'pctChange',  type: 'float'},
        {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
    ]
});

It’s a backward compatible approach, so it’s possible to define the data format in the same way in newer versions, including Ext JS 6. But the proper way to do it would be a definition of a separate Model class, where we can define fields and other logic related to the data.

  1. Create a Model class
      1. Create app/model/Company.js file with this content:
    Ext.define('Migration.model.Company', {
        	extend: 'Ext.data.Model'
    });
    
      1. Copy fields property from Ext JS 3.4 store to our model:
    Ext.define('Migration.model.Company', {
        extend: 'Ext.data.Model',
        fields: [
            {name: 'company'},
            {name: 'price',      type: 'float'},
            {name: 'change',     type: 'float'},
            {name: 'pctChange',  type: 'float'},
            {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
        ]
    });
    

    The Store stays basically the same as in Ext JS 3.4. It is a collection of records (instances of a Model class).

  2. Create a Store class
      1. Create app/store/Company.js file with this content:
    Ext.define('Migration.store.Companies', {
        extend: 'Ext.data.ArrayStore',
        alias: 'store.companies' 
    });
    
      1. Our Store class should use our newly created Model:
    Ext.define('Migration.store.Companies', {
        extend: 'Ext.data.ArrayStore',
        alias: 'store.companies',
        requires: ['Migration.model.Company'],
        model: 'Migration.model.Company'
    });
    

How can I Migrate the View?

The basic usage of Grid Panel stays the same as in Ext JS 3.4. The main difference is that now we need to define our Grid Panel in a separate View class.

    1. First we should create an empty template View class for our Grid Panel. Run the following command from the migration folder:
sencha generate view company.Grid
    1. Edit app/view/company/Grid.js file:
      1. Set base class to Ext.grid.Panel (not Ext.grid.GridPanel like it was in Ext JS 3.4):
        extend: “Ext.grid.Panel”
      2. Add xtype: ‘companygrid’ property, this is the reference to our Grid Panel that we will use later
      3. Remove html property
    2. Copy the Ext JS 3.4 grid column definition and other properties of Grid Panel into new Grid View and comment out all functions for now (we will migrate them later).
    3. Remove autoExpandColumn: ‘company’ config and add flex: 1 config to the Company column. The flex properties are a new way to manage column width. You can read more about Ext.Component-cfg-flex.
    4. Change icon and getClass properties of action column to iconCls with references to FontAwesome icons.

When you finish, your code should look similar to this:

Ext.define("Migration.view.company.Grid",{
    extend: "Ext.grid.Panel",

    requires: [
        "Migration.view.company.GridController",
        "Migration.view.company.GridModel"
    ],

    controller: "company-grid",
    viewModel: {
         type: "company-grid"
     },    

    columns: [
        {
            id       :'company',
            header   : 'Company',
            width    : 160,
            sortable : true,
            dataIndex: 'company',
            flex: 1
        },
        {
            header   : 'Price',
            width    : 75,
            sortable : true,
            //renderer : 'usMoney',
            dataIndex: 'price'
        },
        {
            header   : 'Change',
            width    : 75,
            sortable : true,
            //renderer : change,
            dataIndex: 'change'
        },
        {
            header   : '% Change',
            width    : 75,
            sortable : true,
            //renderer : pctChange,
            dataIndex: 'pctChange'
        },
        {
            header   : 'Last Updated',
            width    : 85,
            sortable : true,
            //renderer : Ext.util.Format.dateRenderer('m/d/Y'),
            dataIndex: 'lastChange'
        },
        {
            xtype: 'actioncolumn',
            width: 50,
            items: [{
                iconCls: 'x-fa fa-minus',
                tooltip: 'Sell stock'/*,
                handler: function(grid, rowIndex, colIndex) {
                    var rec = store.getAt(rowIndex);
                    alert("Sell " + rec.get('company'));
                }*/
            }, {
                iconCls: 'x-fa fa-plus',
	/*
                handler: function(grid, rowIndex, colIndex) {
                    var rec = store.getAt(rowIndex);
                    alert("Buy " + rec.get('company'));
                }*/
            }]
        }
    ],
    stripeRows: true,
    height: 350,
    width: 600,
    title: 'Array Grid',
    stateful: true,
    stateId: 'grid'
});
    1. Now we need to add our Grid to the Main View. Our Main View is an instance of Ext.panel.Panel, and we just need to add our Grid to Main View‘s items array (using previously defined xtype) and requires array (using class name).
Ext.define("Migration.view.main.Main",{
    extend: "Ext.panel.Panel",

    requires: [
        "Migration.view.main.MainController",
        "Migration.view.main.MainModel",
        "Migration.view.company.Grid"
    ],

    controller: "main-main",
    viewModel: {
        type: "main-main"
    },

    items: [{
        xtype: 'companygrid'
    }]
});
    1. Run the following commands from migration folder:
sencha app build
sencha web start
  1. Navigate to http://localhost:1841/ with your browser to check that the application is working. You should see the following screen:

How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6

How do I Create a ViewModel?

The ViewModel is a new abstraction that was released in Ext JS 5. It manages changes between the View and an associated Model. When we generated our Grid View using Sencha Cmd, the ViewModel class was generated as well.

    1. Edit ViewModel file app/view/main/GridModel.js:
      1. Remove data property from the ViewModel class
      2. Add companies store to the stores config of the ViewModel class
      3. Assign data config of companies store to the data from Ext JS 3.4 code
Ext.define('Migration.view.company.GridModel', {
     extend: 'Ext.app.ViewModel',
     alias: 'viewmodel.company-grid',
     requires: [
          "Migration.store.Companies"
     ],

     stores: {
       companies : {
         type: 'companies',
         data: [
                 ['3m Co', 71.72, 0.02,  0.03,  '9/1 12:00am'],
                 ['Alcoa Inc', 29.01, 0.42,  1.47,  '9/1 12:00am'],
                 …
         ]
       }
     }

});
    1. Bind our Grid to the ViewModel

Now we need to add bind config to our Grid View to bind our grid to companies store from ViewModel:

bind: {
     store: '{companies}'
},

Am I able to Migrate Code into ViewController?

The ViewController is a part of MVVM pattern as well. Individual ViewControllers are created for each related View. They listen for events and execute application business logic. In our case, we will move the commented-out function to ViewController. It will contain handlers for add and delete buttons of actioncolumn and column renderers. ViewController for our Grid View has also been generated by Sencha Cmd.

    1. Move change function from Ext JS 3.4 example into GridController.js file and rename it to columnRenderer.
    2. Move pctChange function from Ext JS 3.4 example into GridController.js file and rename it to pctColumnRenderer.
    3. Move handler function of actioncolumn delete button to GridController.js and rename it to sellStock. Change reference to the store in the code to grid.getStore().
    4. Move handler function of actioncolumn add button to GridController.js and rename it to buyStock. Change Reference to the store in the code to grid.getStore().

When you finish, your GridController.js file should look similar to the following code:

Ext.define('Migration.view.company.GridController', {
    extend: 'Ext.app.ViewController',
    alias: 'controller.company-grid',

    columnRenderer : function(val) {
        if (val > 0) {
            return '' + val + '';
        } else if (val < 0) {
            return '' + val + '';
        }
        return val;
    },

    pctColumnRenderer : function (val) {
        if (val > 0) {
            return '' + val + '%';
        } else if (val < 0) {
            return '' + val + '%';
        }
        return val;
    },

    sellStock: function(grid, rowIndex, colIndex) {
        var rec = grid.getStore().getAt(rowIndex);
        alert("Sell " + rec.get('company'));
    },

    buyStock: function(grid, rowIndex, colIndex) {
        var rec = grid.getStore().getAt(rowIndex);
        alert("Buy " + rec.get('company'));
    }

});
    1. Add references to this functions inside Grid View and replace renderer : ‘usMoney’ to renderer : Ext.util.Format.usMoney:
Ext.define("Migration.view.company.Grid",{
    extend: "Ext.grid.Panel",

    requires: [
        "Migration.view.company.GridController",
        "Migration.view.company.GridModel"
    ],

    xtype: 'companygrid',

    controller: "company-grid",
    viewModel: {
        type: "company-grid"
    },

    bind: {
        store: '{companies}'
    },

    columns: [
        {
            id       :'company',
            header   : 'Company',
            flex    : 1,
            sortable : true,
            dataIndex: 'company'
        },
        {
            header   : 'Price',
            width    : 75,
            sortable : true,
            renderer : Ext.util.Format.usMoney,
            dataIndex: 'price'
        },
        {
            header   : 'Change',
            width    : 75,
            sortable : true,
            renderer : 'columnRenderer',
            dataIndex: 'change'
        },
        {
            header   : '% Change',
            width    : 75,
            sortable : true,
            renderer : 'pctColumnRenderer',  
            dataIndex: 'pctChange'
        },
        {
            header   : 'Last Updated',
            width    : 85,
            sortable : true,
            renderer : Ext.util.Format.dateRenderer('m/d/Y'),
            dataIndex: 'lastChange'
        },
        {
            xtype: 'actioncolumn',
            width: 50,
            items: [{
                iconCls: 'x-fa fa-minus',
                tooltip: 'Sell stock',
                handler: 'sellStock' 
            }, {
                iconCls: 'x-fa fa-plus',
                handler: 'buyStock'
            }
            ]
        }
    ],

    stripeRows: true,
    height: 350,
    width: 600,
    title: 'Array Grid',
    stateful: true,
    stateId: 'grid'
});
    1. Navigate to http://localhost:1841/ with your browser to check that the application is working. You should see the following screen:

How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6

Are you ready to get started migrating?

This guide is just a sample of how to migrate your application from Ext JS 3.4 to Ext JS 6. You can find more information in the upgrade guides: