Sencha

Ext 3 to 4 Migration Guide

This guide contains everything you need to know to migrate an application from Ext 3.x to 4.0. For a general overview of the changes between Ext 3 and 4 see the Ext 4 Overview Guide. If you are migrating from a version of Ext prior to 3.0 then it's strongly recommended that you first have a look at these resources:

We have produced a 2-part video tutorial on Ext 3 to 4 migration, including a step-by-step application migration example. View Part 1 or Part 2.

Overview

If you are just starting out with migrating an Ext 3 application to Ext 4, you'll minimize the time and effort required by working through the sections of this guide in the order presented. Here are the main steps involved:

Initialize Compatibility

Update Existing Ext Includes

As noted in the Overview Guide, adapters have gone away in Ext 4. Existing adapter file includes (including the default Ext adapter) should simply be removed. Your current include might be for a different adapter, but it will look something like this:


// Ext 3
<script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
		

This include can simply be removed since it is no longer necessary and will not be used. For now you should still be referencing ext-all-debug.js as before, just make sure you point to the Ext 4 version. Once you have finished migrating fully to Ext 4 you'll be able to switch to the new bootstrap-based dynamic loading scheme for development, but for legacy code you must still use the single build file (your legacy classes will not yet work with the dynamic loader).

Add the Ext 3 Compatibility Layer

The JavaScript required for Ext 3 compatibility is split into two files, one for Ext Core and one for Ext JS. This enables any site that only uses Ext Core to have a compatibility layer that does not include irrelevant Ext JS framework code. A typical Ext JS application will require both files.

To enable Ext 3 compatibility simply include the following lines after ext-all(-debug).js (again adjusting your paths as needed):


<script type="text/javascript" src="path/to/ext3-core-compat.js"></script>
<script type="text/javascript" src="path/to/ext3-compat.js"></script>
		

Putting it All Together

If you got everything right you should end up with code in your header that looks very similar to this:


<!-- The default Ext theme, same as Ext 3 -->
<link rel="stylesheet" type="text/css" href="path/to/resources/css/ext-all.css" />

<!-- Ext 4 framework -->
<script type="text/javascript" src="path/to/ext-all-debug.js"></script>

<!-- Ext 3 Compatibility (remove after migration is complete) -->
<script type="text/javascript" src="path/to/ext3-core-compat.js"></script>
<script type="text/javascript" src="path/to/ext3-compat.js"></script>

<!-- Additional Ext overrides and application-specific includes here -->
		

Fix Breaking Changes

The vast majority of breaking changes have been aliased in the compatibility layer so that existing code should be mostly functional under Ext 4 as-is. For anything that could not be made compatible we've included the following checklist. If you are using the compatibility layer and still hitting runtime errors you'll want to check here first.

NOTE: This section is still in-progress, and so is not 100% complete. If you find any additional breaking changes that are not covered here, please report them in the Ext 3 to 4 Migration thread in the Sencha forums.

Ext.lib

In Ext 3, the Ext.lib namespace is the internal, underlying foundation of Ext Core. It provides the core interfaces implemented by each third party framework adapter for providing DOM functions, events, Ajax, animation and more, and the implemented versions of the Ext.lib interfaces comprise the Ext base adapter. All classes under the Ext.lib namespace are considered to be internal to the framework and should not be called directly by code outside of Ext JS.

In Ext 4, since adapters are no longer supported, the need for Ext.lib as a separate namespace has gone away and its functionality has now been merged into other classes. If you are calling any methods directly on classes in the Ext.lib namespace you will have to adjust them as necessary. Since these are considered private classes, we have not gone through as extensive an effort to make them backwards-compatible as we've done for the public Ext JS API (although we have done so where practical). For most people this change will have no direct effect on application code, but we felt it worth noting.

Charts

The charting API has changed drastically from Ext 3.x. The new package is much more powerful and the API is more expressive now in Ext 4, but unfortunately because of the differences it could not be made compatible via the compatibility layer. The best approach for charts is to simply look through the new API and browse the new examples and use those to manually upgrade any existing charts you might have. You'll likely find new capabilities in the Ext 4 charts that go beyond what your previous version could do, so this effort will be well worth a little extra time during your upgrade.

Registering Custom XTypes

The new class system is based on string class names internally. In 3.x the ComponentMgr simply cached class definitions by reference for later lookup by xtype. In Ext 4 the underlying mechanisms for class creation, subclassing, reflection, etc. all rely on each class being assigned an explicit class name, and that must be done programmatically. Unfortunately the default syntax for registering types via Ext.reg will no longer work, and cannot be automatically aliased for you.

The proper fix is to convert all code to use the new Ext 4 class system, defining classes via Ext.define. However, this is a significant change that may have a large impact on getting your application up and running quickly. A quicker approach to bootstrapping your app to run under the compatibility layer is to simply edit any existing Ext.reg calls you may have to pass a class name string instead of a class reference. For example:


// Ext 3:
Ext.reg('mycoolclass', Ext.ux.MyCoolClass);

// Ext 4 (compatibility mode only, optional)
Ext.reg('mycoolclass', 'Ext.ux.MyCoolClass');

// Ext 4 (proper approach, type is automatically registered)
Ext.define('Ext.ux.MyCoolClass', {
	...
});
		

The Ext.reg function has been aliased to the new Ext.ClassManager.setAlias function in the compatibility layer, so calling it this way will actually define your class within the new class system as a shortcut to altering your entire class definition. You'll need to do that eventually to take full advantage of the new class system (including defining your dependencies, adding mixins, etc.), but this may prove to be a convenient way just to get your custom classes up and running quickly if you have a lot of them defined.

Note: The same applies to registering plugins via Ext.preg also.

Date

All of the native JavaScript Date extensions from Ext 3 have been applied in the compatibility layer, and where possible, appropriate console warnings are also included. Unfortunately there are some static Date properties that could not be aliased as methods, and in those cases console warnings could not be included. Because of that, any code referencing those properties will silently continue to work when running in compatibility mode, but will then break when the compatibility layer is removed. If you follow these guidelines in addition to fixing any console warnings you may receive you should be able to fully migrate any Date-related code without incident.

Static Properties

These property references are simple to fix since they are direct mappings between the native Date object and the new Ext.Date class. For each of the following properties all you have to do is change the Date reference to Ext.Date. For example:


// Ext 3:
Date.useStrict = true;
Date.parseFunctions['my-date-format'] = function(){ ... };
Date.monthNames = ['JanCustom', 'FebCustom', ... ];

// Ext 4:
Ext.Date.useStrict = true;
Ext.Date.parseFunctions['my-date-format'] = function(){ ... };
Ext.Date.monthNames = ['JanCustom', 'FebCustom', ... ];
		

Here is the complete list of static Date properties that will need to be prefixed with Ext.Date:

  • useStrict
  • parseFunctions
  • formatFunctions
  • defaults
  • dayNames
  • monthNames
  • monthNumbers
  • formatCodes
  • MILLI
  • SECOND
  • MINUTE
  • HOUR
  • DAY
  • MONTH
  • YEAR

Static Methods

These methods are aliased with console warnings in the compatibility layer so they should be easy to catch during debugging. However since it will likely be most convenient to replace all Date references at one time, we've listed them here for reference. Like the properties above, these static methods also need be prefixed with Ext.Date instead of just Date. For example:


// Ext 3:
var dt = Date.parseDate("2006-01-15", "Y-m-d");

// Ext 4:
var dt = Ext.Date.parseDate("2006-01-15", "Y-m-d");
		

Here is the complete list of static Date methods that will need to be prefixed with Ext.Date:

Prototype (Instance) Methods

These methods are also aliased with console warnings, but as above we've listed them here for reference. Since these are instance methods and not static methods (they are called on an instance of a date, not on the Date object directly) the fix is slightly different than above. In these cases there will not be a static reference to Date — you'll still have to prefix the method call with Ext.Date but whatever date instance is being operated on will also have to become the first argument to the method. This is because all methods on the Ext.Date class are static, so they aren't aware of the date instance being operated on by default (unlike the previous instance methods, in which the this scope inside each method was the date instance itself). For example:


// Ext 3:
var myDate = new Date('10/29/2006').add(Date.DAY, 5);
var isLeap = myDate.isLeapYear();
var copy   = myDate.clone();

// Ext 4:
var myDate = Ext.Date.add(new Date('10/29/2006'), Ext.Date.DAY, 5);
var isLeap = Ext.Date.isLeapYear(myDate);
var copy   = Ext.Date.clone(myDate);
		

Here is the complete list of Date instance methods that will need to be fixed accordingly:

  • format
  • getTimezone
  • getGMTOffset
  • getDayOfYear
  • getWeekOfYear
  • isLeapYear
  • getFirstDayOfMonth
  • getLastDayOfMonth
  • getDaysInMonth
  • getSuffix
  • clone
  • isDST
  • clearTime
  • add
  • between

One drawback to transitioning to static methods from instance methods is that we lose the convenient ability to chain multiple date operations together on one line since the date instance returned from each call will not have the next method defined on its prototype. One small tip is to alias Ext.Date as a variable if you need to make many calls on it within the same block of code. For example:


// Ext 3:
var myDate = new Date('10/29/2006').add(Date.DAY, 5).add(Date.HOUR, 12).format("c");

// Ext 4:
var Dt = Ext.Date,
    myDate = Dt.add(new Date('10/29/2006'), Dt.DAY, 5);

myDate = Dt.add(myDate, Dt.HOUR, 12);
myDate = Dt.format(myDate, "c");
		

While the new syntax is not as concise, it's a necessary trade-off to avoid potentially clashing not only with other JavaScript frameworks but also with future versions of the ECMAScript specification.

Forms

The handling of form processing and submission has changed in Ext 4. Form field value management has been completely decoupled from the DOM, meaning that hidden fields are no longer required to manage values for non-input-based fields, and FormPanels no longer wrap their contents in a <form> element. Instead values are managed by the component layer and form elements are dynamically constructed at submit time as needed. In general this makes managing forms and field values much simpler and more flexible.

In Ext 3 you could render an input with type="submit" into a form and allow the default browser submit to post the field values. Because of the changes in Ext 4, all form submission must now go through the Ext forms API, either by using a FormPanel or by attaching an Ext.form.Basic instance to another Ext container (hidden fields are no longer managed by default since they aren't needed). If you have any Ext fields or forms being processed outside of the forms API they'll have to be updated accordingly. Note that the Ext.form.Basic.standardSubmit option and accompanying StandardSubmit action class are still fully supported, so you can still perform standard, non-Ajax form submissions. You simply cannot submit Ext form fields outside of the forms API going forward.

Component

3.x4.0Notes
Config Options
applyTo renderTo In Ext 4 many components support generating different markup dynamically based on the browser (in Ext 3 the least common denominator markup was always created). This allows optimizing markup size and reducing layout/styling complexity in most cases. However it also means that generically applying a component to markup can no longer be practically supported as the markup will not be consistent between platforms.

Going forward you should use the standard renderTo config (or render method) for rendering all components. Note that you may need to include additional config options within your component's init code to implement any portions of the component that were previously defined in the markup (e.g., defining the header for a panel).
Methods
applyToMarkup render See the comments above for the applyTo config.

Element

3.x4.0Notes
Methods
down <—> child child <—> down These methods have been reversed so that the meanings now make more sense logically. Child will now areturn only a direct child that matches the selector, while down will now return a matching child at any depth. Unfortunately these cannot be aliased since Ext also uses them internally, and reassigning the old behavior would break Ext. You should search for all instances of these methods and verify their behavior under Ext 4. Note that if you get errors like this.someEl is undefined this change should come to mind as something to look for.

PagingToolbar

A general change to be aware of is that the page indices in PagingToolbar in 3.x were zero-based. In 4.0 paging is now delegated to the underlying store, which uses one-based indexing. Any custom logic related to paging should therefore be reviewed for any impact from this change.

3.x4.0Notes
Properties
cursor store.currentPage Since the PagingToolbar now delegates to the underlying store for management of paging at the data level, it no longer maintains its own pointer to the current page. If you need to know the current page simply access the property on the store that was configured for the PagingToolbar. NOTE: cursor was previously zero-based, while store's currentPage property is one-based, so existing logic may have to change to account for that.
afterTextItem
inputItem
first
prev
next
last
refresh
child('#afterTextItem')
child('#inputItem')
child('#first')
child('#prev')
child('#next')
child('#last')
child('#refresh')
These properties correspond to the buttons and input elements within the PagingToolbar. They are still available, but no longer as explicitly-defined properties. Instead use the new ComponentQuery syntax to access them as needed.
Events
beforechange (see notes) The second param passed with the beforechange event in 3.x was a params object that contained the start and limit params to be sent to the store. In 4.0 the PagingToolbar does not manage paging and does not directly track those values. Now the second param passed with beforechange is simply the page number that will be loaded on change.
change (see notes) The second param passed with the change event is a pageData object. In 3.x it contained properties called: total, activePage and pages. In 4.0, activaePage was renamed to currentPage and pages was renamed to pageCount (total is unchanged). In 4.0 pageData also contains two new properties: toRecord and fromRecord.

Panel

3.x4.0Notes
Properties
header header.getEl() In Ext 3, a panel's header property referred to its header Element. In Ext 4 it now refers to the new header Container (which has a layout, child items, etc.). Unfortunately this cannot be aliased without potentially overwriting valid header objects so any references to Panel.header as an Element must be updated manually.

Store

3.x4.0Notes
Properties
recordType model In Ext 3, you could use the recordType property as a generic record constructor if you had not explicitly defined a named record constructor. In Ext 4 since records are now models, this constructor property is called model. For example, you can do something like var rec = new someStore.model(data);

Migrate to Ext 4

Any compatibility changes that could be aliased in the compatibility file will provide browser console messages with details on how to properly resolve the issue. Here are some pointers for best using the compatibility file to move to Ext 4.

If you have not already watched the Ext Migration video tutorials, now would be a great time to do so. View Part 1 or Part 2.

Use Firefox + Firebug for debugging

While all modern browsers now support the console object and can be used for debugging Ext, there are a couple of reasons to use Firefox and Firebug specifically to work through compatibility issues:

Ext.Compat Options

ignoreInfo

By default the compatibility layer may include a lot of informational issues (via console.info). While these are helpful in providing things to look out for during migration, they usually do not indicate specific issues in your code. They are typically general things to watch for or warnings about behavior that may have changed (but did not necessarily break compatibility).

It might be helpful to temporarily disable the display of these informational messages while you focus on clearing up warnings and errors, and you can easily do so by simply including this code anywhere after the compatibility files are loaded:


Ext.Compat.ignoreInfo = true;
		

showErrors

By default all compatibility issues are output to the console as warnings (via console.warn). This allows you to easily distinguish compatibility warnings from actual runtime errors. However, all you end up with is the message itself with no context about where it originated in code.

If you use Firebug, one extremely handy feature it provides (and other browser consoles do not) is that if you call console.error() instead of console.warn() it also captures the stack trace at the point of execution and displays it as part of the console message. Even better, the stack trace can be expanded and is linked directly to the relevant line of code for each layer in the stack. This means that you can click through each compatibility warning directly to the line of code that raised the warning so you can see what to fix in context. To enable this mode simply include this line of code anywhere after the compatibility files are loaded:


Ext.Compat.showErrors = true;
		

silent

If you get to the point where you want to provide your application to end users for testing, but you still require the compatibility layer to be in place, it is very simple to turn off all console messaging while retaining the compatibility functionality by setting this property after the compatibility files are loaded:


Ext.Compat.silent = true;
		

© 2006-2011 Sencha Inc.