Despite the fact that the fourth version of the ExtJS framework has been published for a long time, there are not too many materials on this version. And if we consider that in the fourth version, the API has been significantly reworked, the structure of classes and the proposed architecture of the application, then I think there is something to talk about.
In this article I will try to tell my impressions of the framework in the context of porting the existing code base to the new version; I will also try not to forget about the pitfalls and links to useful (and not so) help pages.
Ext4, ugh. Not backward compatible with Ext3, and imposing all ordering to make it "easier". The Windows Vista of Javascript frameworks
(one of the comments on
stackoverflow.com )
')
ExtJS 4 is incompatible with previous versions of the framework.
This means that your application written for any other version of the framework will not work (except in trivial cases). It will happen for the following reasons:
- Changed requirements for application architecture
- The class structure has changed
- Partially changed API semantics
Application architecture
The most significant change concerns the architecture: ExtJS4 now preaches the MVC pattern on the client side. All the “business logic” of your component must be moved to the “Controller” entity, and what the visual interface provides is to make the “View”; The logic of working with data should be moved to the “Models” layer (to which
Ext.data.Model itself , previously known as
Ext.data.Record , and
Ext.data.Store storages,
belong directly ).
In fact, all visual components - panels, tables, trees, etc. - These are claimants to be a representation or part of it. The possibility of nesting (aggregation) of visual components is now possible only for the view level: controllers exist, in fact, in a flat layer.
Representations report "upstairs" about changing their state through the mechanism of events.
Important from the point of view of the "business problem" events must be processed in the controller. For this, each controller has a magic
control () method, with which it subscribes to events coming from some part of the view. The controller tells you who it wants to receive events from using the CSS-like syntax called
ComponentQuery :
Ext.define('My.controller.Header', { extend: 'Ext.app.Controller',
Here it is important to understand the following things:
- Each controller “sees” the entire available viewport, so it is often necessary to specify that you need a well-defined socket or a completely unique button, and this is not always easy.
- ComponentQuery, written in a parameter to control (), is an event selection rule, and it acts dynamically. This means that for any event from view the application decides whether this handler can be called in the controller or not.
Thus, what was previously encapsulated in one component, which could be easily reused, now turns out to be broken into several separate parts: a set of "mindless" representations, a set of models and a set of controllers. This creates an advantage for small applications with statically defined elements and serious difficulties for pages with dynamic component creation (you can read about such a problem, for example,
here ).
Classes and components
In the fourth version of the framework, the structure of standard classes has been seriously revised. The names of the classes themselves have become more concise, the division of responsibilities between the classes is more thoughtful.
I was pleased, for example, that the read / write logic for the Store is now really encapsulated in
Ext.data.proxy.Proxy (earlier, for example, to override the work with the RESTful server, it was necessary to overlap both the corresponding methods in Proxy and in the repository - in the onWrite, onRead and onUpdate methods).
In addition, there is no longer that strange situation with
GroupingStore , when you had to choose whether the Store will work with JSON (JsonStore), XML (XmlStore) data or it will be able to group data (GroupingStore) for the table, and all these 3 classes were on one hierarchy level.
In some cases, the behavior of objects has become more predictable. So, now before the component is rendered (before the 'render' event), its items collection is of type MixedCollection, not an array,
as before (a trifle, but nice), and the Ext.grid.Panel table is now self-processing the selection loss after reloading the storage (earlier this situation had to be described manually).
ExtJS 4 does not change the prototypes of standard javascript classes.
So, now the utilitarian functions that were previously added to the prototypes (Function.
CreateDelegate (), String.
Format (), Array.
IndexOf ()) are rendered into separate sinlet objects (Ext.Function.
Bind (), Ext.String.
Format ( ) and Ext.Array.
indexOf () respectively).
API changes
In most cases, the names of the methods also became more concise, but as a fact, they have changed. Accordingly, you will need to spend time trying to make sure everything in your application works correctly. For example, the SelectRow () method of the SelectionModel now corresponds to the new select ().
From the bad: the semantics of working with storages working with remote data has changed a lot. I was surprised when it turned out that the Store no longer has “pens” in order to add an additional set of parameters for the request to the server. No analogues setBaseParam () or load (params) is no longer provided.
The underlying Proxy class can work with any set of parameters, as before, but at the Store level there is a well-defined set of keys that are given to the Proxy.
UPD The comments suggest that
you can actually pass additional parameters (thanks to
MrSLonoed for the addition).
Obviously, as an alternative to
setBaseParam (), the repositories support the so-called filters and sorters (Filters and Sorters). These entities can be used both locally (working on an existing dataset) or remotely (being sent to the server as parameters). What is characteristic: for filters and sorters there is no flexible possibility of serialization into HTTP parameters. So, the filters will always be serialized as follows.
mywebserver?{otherparams}&filters={your serialized filters}
You can control the serialization of filters only within the
{your serialized filters}
, and you will not be able to get rid of the filter parameter using standard tools.
Here is an example of how filters can be used to add additional parameters to a query:
Ext.define('My.proxy.Ajax', { extend: 'Ext.data.proxy.Ajax', alias: 'proxy.myajax', filterParam: '', getParams: function (params, operation) { params = this.callParent(arguments); var filters = operation.filters; if (this.filterParam === '' && filters && filters.length) { Ext.apply(params, this.encodeFilters(filters)) } return params; }, encodeFilters: function (filters) { var f, po = {}, i; for (i = 0; i < filters.length; ++i) { f = filters[i]; po[f.property] = f.value; } return po; } } );
UPD: Pay attention to an important detail: by default, the added filters will work both remotely and locally. This means that if you add the filter “q = myValue”, this filter will be serialized into the corresponding HTTP parameter (which is good), but then it will be applied to the Store after loading. And to catch the reason for the disappearance of records, when they were all received, you can also take a long time. Therefore, look at the parameter Store.
filterOnLoad .
The second unpleasant moment is also associated with AJAX. For some reason, ExtJS4 lacks the simple case of Writer, which sends an object as a set of HTTP key-value parameters. Its implementation is trivial, but the “sediment remains”:
Ext.define('My.data.writer.Http', { extend: 'Ext.data.writer.Writer', alias : 'writer.http', writeRecords: function(request, data) { if (Ext.isArray(data)) { data = data[0]; } Ext.apply(request.params, data); return request; } } );
Dynamic loading
The new version of the framework provides the ability to dynamically load JS-resources (including cross-domain and even for the
file://
protocol - for example, the help can be opened simply as an html-file from the file system). In this regard, it is recommended that in each of its classes it is explicitly prescribed the names of the classes or packages on which this class depends.
This is done by calling Ext.require () or using the
same section in the body of the class declaration.
When the source code is enabled, ExtJS ensures that the class graph is correctly loaded in such a way that all dependencies are correctly taken into account.
A new requirement related to the location of source codes in the file system is associated with the same feature: the full class name must unambiguously determine the location of the file in the file system (as is customary, for example, in Java or in the Zend Framework in PHP).
ExtJS sources now also have several options:
- ext-all-debug.js
- ext-all-debug-w-comments.js
- ext-all-dev.js
- ext-all.js
- ext-debug.js
- ext-dev.js
- ext.js
The ext * .js files that do not contain the all suffix in the name are sources with dynamic loading enabled. Such resources should be used only in debug mode.
By the way, “accidentally” included dynamic resource loading is another source of ExtJS “silent” crashes, if the resource being loaded contains a syntax error. However,
JSLint has not been canceled yet.
More information about the goals of each of the options "linking» ExtJS can be found
here .
Read the source and be good programmers!
Thanks for attention