PDA

View Full Version : API Changes in Ext JS 4.1



dongryphon
31 Oct 2011, 11:12 AM
** UPDATE: The content of this thread has been summarized in the following Guide. If we've missed anything, please start a new thread to let us know. And thanks for all your help! **

http://docs.sencha.com/ext-js/4-1/#!/guide/upgrade_41


This thread is intended to capture all the breaking changes as we encounter them. It was our goal to avoid breaking or changing our API as much as possible in this release, despite the scope of the internal changes. In many cases then, if the API has changed in 4.1, this could be a bug that we need to address. In some cases, the API change may be necessary.

I will try to keep the running list up to date in this post as folks reply with their findings.



API
Change
Resoluton


Component render
Only called on top-most components
In previous releases, the render method was used to render all components in a top-down traversal. In 4.1, rendering is performed in memory as markup which is then written to the DOM. This means that the render method of child components is not called. Code in the render method should most likely move to either beforeRender (new to 4.1) or afterRender. For best performance, it is desirable to make style or add/removeCls adjustments in beforeRender so that these values will be generated in the initial markup and not made to the DOM element as it would be in afterRender.


Component onRender
Elements now exist in DOM at time of call
In previous releases, the component's primary element ("el") was created when the parent class method was called. This is no longer possible due to bulk rendering. Any logic that was performed prior to calling the parent method can be moved to the new beforeRender method


Component renderTpl
Render Templates now call helper methods
As part of bulk rendering, a renderTpl now calls helper methods on the template instance to inject content and container items. This can be best seen in the default renderTpl for Components:


renderTpl: '{%this.renderContent(out,values)%}'

and Containers:


renderTpl: '{%this.renderContainer(out,values)%}'



callParent in override
calls overridden method
This was changed as part of formalizing Ext.define/override. In 4.1, it is now possible to name and require overrides just as you would a normal class:


Ext.define('My.patch.Grid', {
override: 'Ext.grid.Panel',

foo: function () {
this.callParent(); // calls Ext.grid.Panel.foo
}
});

The above code in 4.0 would have called the base class "foo" method instead. The callOverridden method was needed to do the above. To bypass the overriden method, you just need to do this:


Ext.define('My.patch.Grid', {
override: 'Ext.grid.Panel',

foo: function () {
Ext.grid.Panel.superclass.foo.call(this);
}
});

It is possible for a class to even "require" its own overrides. This enables breaking up a large class into independent parts expressed as overrides (a better approach than "AbstractFoo" and "Foo").


FocusManager
subscribe
For details, see http://www.sencha.com/forum/showthread.php?153938-Where-is-Ext.FocusManager.subscribe()&p=678781&viewfull=1#post678781


Component
doComponentLayout
This method can still be called to perform a layout of the component, but its internals are quite different. As a component author, this method can no longer be overridden to perform a custom layout since it will not be called internally. Instead you can override afterComponentLayout which is given the new size and old size as parameters or you can respond to the resize event. If you are writing a derived component, the method override should be preferred - just don't forget to callParent.

One other note: the size of the component should not be changed by this method. The size has been determined already. If the size is changed again, this could lead to infinite recursion at worst (since afterComponentLayout will be called again) or just wrong layout.


config
setters are called to set default values
In 4.0, the config mechanism in Ext.define would create getter and setter methods, but the default value would bypass the setter. In this build, we have a partial solution that uses initter methods but that will change to sync with Touch 2 and will simply call the setter. This can effect the timing of the first call to the setter method but is needed because setters were designed to enable transformation-on-set semantics. In Beta 1, this timing is much closer to 4.0.


Ext.data.Model
The model store property is now an array of stores.
A single record can belong to more than 1 store, especially in the case of a tree. As such, we need to track a list of all the stores that the model belongs to


Ext.layout.container.Border
Split components are added to the container
When configuring components with split: true, the layout will now insert extra splitter components as siblings of the current components. This allows for the layout to be much less complicated and also allows the ability to dynamically modify regions.









Fixed in Beta 1



API
Change
Resoluton


Component style config
CSS names cannot be 'camelCase'
This is a bug in the bulk rendering mechanism. We need to de-camelize these names into proper CSS names.

LesJ
1 Nov 2011, 6:28 AM
Don, by my understanding, marginTop in the example below should be changed to 'margin-top'.

Is this correct?


Ext.define('MyPanel', {
extend: 'Ext.form.Panel',
...
style: {
marginTop: 5,
padding: '4 0 0 0'
},
...

stahlman
1 Nov 2011, 6:50 AM
@LesJ - It was my understanding that this is not so much an intentional change but a bug (which hopefully will be fixed). See the following thread:
http://www.sencha.com/forum/showthread.php?152673-Rendering-incorrect-when-camel-case-property-names-used-in-component-s-style-object

LesJ
1 Nov 2011, 7:57 AM
>>> We need to de-camelize these names into proper CSS names.

Well, then fix it =D>

I misunderstood that this is an action item for me (as a developer) and that my current code that uses camel case will no longer work.

aenigmatic
1 Nov 2011, 8:54 AM
I have encountered problems with previously overridden methods. The Ext.foo.override() method is listed as depracated, but it seems all out broken to me. I have had good luck switching to Ext.define, and there is good documentation, but just something to add to the list potentially.

dongryphon
1 Nov 2011, 12:33 PM
@LesJ

Sorry for the confusion. It is a bug in the framework and will be fixed ASAP since it is a critical compatibility problem. If you need this to test PR1, sadly, you will need to change your code or just ignore the visual problems it creates.

dongryphon
1 Nov 2011, 12:37 PM
@aenigmatic

While that form is deprecated it is fully supported in 4.x and may or may not remain beyond that. What seems to be broken about it? Perhaps an example would illustrate.

fyi... the reason we deprecated it is because it cannot be "managed" as part of a build or by the loader (hence the switch to Ext.define for overrides).

dongryphon
4 Nov 2011, 11:58 AM
Added comments to 1st post about overrides of the render method...

dongryphon
15 Nov 2011, 2:39 PM
>>> We need to de-camelize these names into proper CSS names.

Well, then fix it =D>

I misunderstood that this is an action item for me (as a developer) and that my current code that uses camel case will no longer work.

Just a note that this is fixed and will be in the next build of 4.1.

jay@moduscreate.com
16 Nov 2011, 5:06 AM
Don, thanks for taking the time to write this. definitely helpful for my writing efforts :)

dongryphon
30 Nov 2011, 2:48 PM
The API to FocusManager has changed somewhat and should be much better as well as more efficient. See http://www.sencha.com/forum/showthread.php?153938-Where-is-Ext.FocusManager.subscribe()&p=678781&viewfull=1#post678781

dongryphon
30 Nov 2011, 2:53 PM
I have encountered problems with previously overridden methods. The Ext.foo.override() method is listed as depracated, but it seems all out broken to me. I have had good luck switching to Ext.define, and there is good documentation, but just something to add to the list potentially.

If you can reproduce a bug with override, please report it in a new thread (see also http://www.sencha.com/forum/showthread.php?138165-How-to-report-a-bug). Thanks!

dongryphon
1 Dec 2011, 9:20 PM
Dmitry Pashkevich asked a good question in response to the blog post http://www.sencha.com/blog/whats-new-in-ext-js-4-1.

The question was about how doComponentLayout works now in 4.1 and how that would effect a component author who might have overridden this method. The answer to this has been added to the top of this thread.

dongryphon
23 Dec 2011, 1:04 PM
The bug with style names not supporting camelCase has been fixed in Beta 1.

LesJ
10 Jan 2012, 1:23 PM
There have been class configuration changes in 4.1 (that are not present in 4.0.7).

For example, adding a config variable generates corresponding 'apply' and 'update' methods. The 'update' method is new in 4.1.

See more info here (http://www.sencha.com/learn/sencha-class-system)

goreng
29 Mar 2012, 8:12 AM
Hello Sencha Team,

I've got some problems to upgrade my Ext4.0.7 application to Ext4.1. I haven't found a detailed description, which changes are made to the Reader-Class, may be someone here can help me with this.

I have implement a "native" Coldfusion-Reader-Class. Therefore I extend Ext.data.reader.Json and override the readRecords function:



readRecords: function(data) {
this.checkColumns(data);
return this.callParent([data]);
}


The new checkColumns function build nothing else than extractorFunctions based on the data.
(
The "native" Coldfusion way to send data as json is for example:


{
COLUMNS : ["COLUMN1","COLUMN2"],
DATA : [
["data1.1","data2.1"],
["data1.2","data2.2"]
]
}


)

So I only have to read the fields-Config and map the right array-index from the COLUMNS-array regarding the field.mapping or if not provide the field.name.

After finding the right index for a field, I build the current extractorFunction in the checkColumns function by :



//Loop over the fields config array
var fields = this.model.prototype.fields.items, i = 0, length = fields.length, extractorFunctions = [], map, mIndex;
for (; i < length; i++) {
...
//code for finding the correct array index 'mIndex' (still working correct in Ext4.1)
...
extractorFunctions.push(function(index) {
return function(data) {
return data[index];
};
}(mIndex));
}
//Assign the new extractorFunctions to the reader
this.extractorFunctions = extractorFunctions;



This works very fine in 4.0.7, but not in 4.1.

Is there something changed in the base Reader class, which override my extractor functions?

Animal
29 Mar 2012, 1:44 PM
Yes, the extraction of data from the raw object into each record's data property has changed.

Instead of generating an accessor function for every field, and then calling that in a loop for every field of every record read, we do something better in 4.1

We generate a function which extracts all fields from a raw row into the data property in one shot.

This function is formatted so that if you step into it, you will be able to read what it does and step through in the debugger.

So look at line 421 in Reader, you will see



me.convertRecordData(convertedValues, node, record);


"node" is the raw data row. "convertedValues" is a reference to the new record's data object.

That is the generated function which does the field converting and copying.

If you step in, you will be inside a function which looks a little like this one which is used by the ArrayReader of the basic array grid example:



function(dest, source, record) {
dest["company"] = (source[0] === undefined) ? __field0.defaultValue : source[0];
dest["price"] = __field1.convert((source[1] === undefined) ? __field1.defaultValue : source[1], record);
dest["change"] = __field2.convert((source[2] === undefined) ? __field2.defaultValue : source[2], record);
dest["pctChange"] = __field3.convert((source[3] === undefined) ? __field3.defaultValue : source[3], record);
dest["lastChange"] = __field4.convert((source[4] === undefined) ? __field4.defaultValue : source[4], record);
}


You can see that it will be must more efficient that looping through field access expressions.

You can also see that it is created as a closure inside a scope which captures useful references.

"me" is a reference to the Reader. And you have vars set up which reference the Field definitions for each Field.

Your custom reader needs to implement a createFieldAccessExpression method. It is private now, so custom readers are not officially supported even though they obviously have been around for a while.

This function will be passed field, fieldVarName, dataName

field is a reference to the Ext.data.Field object which describes the field you are creating an access expression for.

fieldVarName is a string which is the name of the var which references that Field object in the scope of the function that will be using your returned expression. So the code you create can use this string as a var name. In that example above they are "__field1", "__field2" etc (We cannot call them your defined field names in case they are reserved words... we actually made that mistake in beta code)

dataName is the name of the object from which the data is being extracted. So it's the name of the var which contains ["data1.1","data2.1"]

Animal
29 Mar 2012, 1:50 PM
But that looks like you just need an ArrayReader. Can you use an ArrayReader with your returned data?

goreng
30 Mar 2012, 1:32 AM
@animal

Thank you for your advice. I'll look at the detail today.

Yes, that's right. Basically, I need an ArrayReader. But the problem with the ArrayReader is that I need fixed indices to configure it. But fixed indices are not given in the application or better in the data return and may change with each call. Only the specific fields are fixed, but not the current index of the field in the array in the data return. However, since the "COLUMNS" are sent, which describing the current field indices, I can use them to define the "dynamic" indexes (you can also be interpreted it as a metaChange event on each call ).

To implement my "CfQueryReader" I mixed the techniques of the JsonReader and the ArrayReader to get the best of both ;) . I really like the way how to configure a JsonReader, because it is more "readable" for me, and the ArrayReader does not need the "data overhead" to combine each field data set with the field name.

ykey
16 Apr 2012, 5:36 AM
Ext.data.NodeInterface#decorate now expects the model class instead of a model record. Could this check for a record and extract its class as well to not break backward compatibility with 4.0?

marcelofarias
16 Apr 2012, 3:53 PM
Thanks for you report. It should be fixed in 4.1. Please look for EXTJSIV-5952 in the release notes.

dongryphon
12 May 2012, 1:36 PM
The content of this thread has been summarized in the following Guide. If we've missed anything, please start a new thread to let us know. And thanks for all your help!

http://docs.sencha.com/ext-js/4-1/#!/guide/upgrade_41