Hi, Habr. I want to share my experience of using Ext JS to quickly build complex interfaces I am a front-end developer at EnglishDom, and we are developing online services for learning English. I have 6 years of commercial experience in the frontend, and 4 of them I work with Ext JS. I also have experience with Backbone, React and Ember. Today we will talk about Ext JS, I will tell my usage history, development features and after each small story I will draw a conclusion. I ask everyone under the cat.
A little background
I came to EnglishDom in 2013, and my first task was to develop an administrative panel for the current functionality and for future services. I wanted to take Backbone and Bootstrap or Ember and Bootstrap to blind out of this architecture and write my UI framework. One option was to use
Ext JS as a UI framework, which seemed interesting to me, despite the fact that I had no experience with it.
I went to understand the documentation, watch the examples, and after half a day I wrote the first table (grid) with local data.
Conclusion 1: the threshold of entry is small, everything is clear and simple.')
This module now looks the same as before.

I noticed that in the first 2 days of work I did not write
a single html tag and had already forgotten how the
selectors are written
in CSS . But what I did was
cross-browser .
Conclusion 2: in Ext JS, creating a UI cross-browser is nice and fast.Another point I noticed: these are long (more than two hundred lines) configurations for views, storage (store) and transport (proxy). It was unusual to write them, because instead of definitions I wrote objects nested in arrays, nested in other objects, and so on. This is bad or good - I do not know, but then it was unusual for me.
Conclusion 3: Ext JS code resembles a large configuration file.For example, the table code looks like this: 109 lines and a lot of nesting, and this is without storage, just a view.
Table View CodeExt.define('KitchenSink.view.grid.ArrayGrid', { extend: 'Ext.grid.Panel', requires: [ 'Ext.grid.column.Action' ], xtype: 'array-grid', store: 'Companies', stateful: true, collapsible: true, multiSelect: true, stateId: 'stateGrid', height: 350, title: 'Array Grid', viewConfig: { stripeRows: true, enableTextSelection: true }, initComponent: function () { this.width = 600; this.columns = [ { text : 'Company', flex : 1, sortable : false, dataIndex: 'company' }, { text : 'Price', width : 75, sortable : true, renderer : 'usMoney', dataIndex: 'price' }, { text : 'Change', width : 80, sortable : true, renderer : function(val) { if (val > 0) { return '<span style="color:' + 'green' + ';">' + val + '</span>'; } else if (val < 0) { return '<span style="color:' + 'red' + ';">' + val + '</span>'; } return val; }, dataIndex: 'change' }, { text : '% Change', width : 75, sortable : true, renderer : function(val) { if (val > 0) { return '<span style="color:' + 'green' + '">' + val + '%</span>'; } else if (val < 0) { return '<span style="color:' + 'red' + ';">' + val + '%</span>'; } return val; }, dataIndex: 'pctChange' }, { text : 'Last Updated', width : 85, sortable : true, renderer : Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange' }, { menuDisabled: true, sortable: false, xtype: 'actioncolumn', width: 50, items: [{ iconCls: 'sell-col', tooltip: 'Sell stock', handler: function(grid, rowIndex, colIndex) { var rec = grid.getStore().getAt(rowIndex); Ext.Msg.alert('Sell', 'Sell ' + rec.get('company')); } }, { getClass: function(v, meta, rec) { if (rec.get('change') < 0) { return 'alert-col'; } else { return 'buy-col'; } }, getTip: function(v, meta, rec) { if (rec.get('change') < 0) { return 'Hold stock'; } else { return 'Buy stock'; } }, handler: function(grid, rowIndex, colIndex) { var rec = grid.getStore().getAt(rowIndex), action = (rec.get('change') < 0 ? 'Hold' : 'Buy'); Ext.Msg.alert(action, action + ' ' + rec.get('company')); } }] } ]; this.callParent(); } });
After some time, more complex tasks began to arrive. For example, in one task it was necessary to dynamically change the configuration of the view, in the other to change the standard transport for the backend, in the third one you need to get the context of the current view in one of the methods. I also noticed that duplicate code already appears in several components.
Conclusion 4: the threshold of entry is small, but building a high-quality architecture will not work right away.To solve these problems, I had to pause and re-read the documentation and relevant sites. Having made a few discoveries, I began to more thoughtfully, scalable, modular and expandable, to write new code and refactor the old one.
Conclusion 5: The framework promotes its architectural approach (MVC and MVVM), following which you will not have bicycles and problemsAfter that, I began to spend more time reading documents. In the documentation, each component has a component hierarchy (chain of inheritance), which modules it uses, you can view the source code of a specific method, see public / private / prohibited / new / chain methods, and a list of all events.
Conclusion 6: The documentation is great, JSDuck is a good tool.This is how the hierarchy of inheritance, dependencies, sub-classes for the table component looks like in JSDuck.

And so the documentation for the
tables.
I wrote mostly simple components, since the tasks were also simple. Most often it is to display a table, make a tree (
treepanel ). But after accepting the new functionality by the product team, they pointed out some disadvantages of the provided interface.
There was a need for another pagination, filtering the table and a couple of small things that were not in the standard set. And they were not even in official plugins.
The tables, for example, have 184 methods and 105 different events. It seems that this should suffice even for the most tricky task and interface.
105 table eventsactivate
add
added
afterlayout
afterrender
beforeactivate
beforeadd
beforecellclick
beforecellcontextmenu
beforecelldblclick
beforecellkeydown
beforecellmousedown
beforecellmouseup
beforeclose
beforecollapse
beforecontainerclick
beforecontainercontextmenu
beforecontainerdblclick
beforecontainermousedown
beforecontainermouseout
beforecontainermouseover
beforecontainermouseup
beforedeactivate
beforedeselect
beforedestroy
beforeexpand
beforehide
beforeitemclick
beforeitemcontextmenu
beforeitemdblclick
beforeitemmousedown
beforeitemmouseenter
beforeitemmouseleave
beforeitemmouseup
beforereconfigure
beforeremove
beforerender
beforeselect
beforeshow
beforestaterestore
beforestatesave
blur
boxready
cellclick
cellcontextmenu
celldblclick
cellkeydown
cellmousedown
cellmouseup
close
collapse
columnhide
columnmove
columnresize
columnschanged
columnshow
containerclick
containercontextmenu
containerdblclick
containermouseout
containermouseover
containermouseup
deactivate
deselect
destroy
disable
dockedadd
dockedremove
enable
expand
filterchange
float
focus
glyphchange
headerclick
headercontextmenu
headertriggerclick
hide
iconchange
iconclschange
itemclick
itemcontextmenu
itemdblclick
itemmousedown
itemmouseenter
itemmouseleave
itemmouseup
lockcolumn
move
processcolumns
reconfigure
remove
removed
render
resize
select
selectionchange
show
sortchange
staterestore
statesave
titlechange
unfloat
unlockcolumn
viewready
It seemed to me that the current functionality is also suitable and it solves the user's problems, but since there was time, it was decided to write the interface, as required. I went to the official forum and on GitHub to look for plugins for these tasks. There were enough of them, of different quality. There were plug-ins that precisely solved the tasks, but they were unofficial, without good documentation, and they had bugs. I had to rewrite them or even rewrite a lot.
Conclusion 7: even though the framework contains many various components and APIs to them, not all tasks can be solved, and open source plug-ins are not always “out of the box” work.The time has passed, and we already had more than 20 sections in the admin panel: they allowed us to fine-tune and manage content, users, student downloads, newsletters, server monitoring and errors. I was happy as a developer - everything worked, there were almost no bugs. At some point, appeals and complaints from admin users began. The problem is that there were lags and lags in their favorite browser.
This was due to the fact that Ext JS creates many DOM nodes, repaint happens a lot, and fps sometimes drops to 0.
The solution to this problem is to optimize the code (there are tips on how to do this) and upgrade the hardware.
Conclusion 8: Ext JS is a “heavy” framework.It also happened that I did not find the answer to my questions. In general, I knew how to solve this problem (another bicycle), but I wanted to write “in the right way”, and left the “bicycle” for the most extreme case. I asked questions on the forum, and surprisingly, I was answered fairly quickly and helped to solve problems.
Conclusion 9: the community actively helps in solving problems and the framework is really alive.Of course, in light of the popularity of open source, with Ext JS, everything is not so simple and clear. About licensing on Habré there is a good
article , comments to it are useful too.
Conclusion 10: you need to carefully read the license and find your version of using the framework.Sencha has many other products. I didn’t use all the tools, but for example, I would love to try
React Ext JS and
Sencha Architect in business, because I hadn’t seen such products before.
Conclusion 11: A good ecosystem that develops.Since our company is very worried about customers and their learning progress, and wants to follow every aspect of training. To accomplish this task, good CRM is indispensable. It was accepted by the technical department to write your instrument, guess - on what? With that we wrote it together with a new digital textbook. The task turned out to be simple and for 1 sprint (10 days) by 2 developers (frontend and backend) a simple MVP CRM was written that aggregated all student and teacher references, created tasks in the system and the system itself was similar to Kanban's board with ticket statuses. And for each treatment, you can solve the problem in a couple of clicks and correspond with the user (parsing email letters and correspondence with the student and teachers).
I’m sure if we chose another framework, this task would take much longer.
This is what this tool looks like.

Tasks can be moved between columns (drag and drop). Each task opens in a modal window. Where you can see the entire history of appeals and decide the ticket itself.
Conclusion 12: Allows you to focus on the business logic of the application and write it from the first minutes of the task.Here I would like to stay in more detail.
I consider this conclusion one of the most important, which I made after a long time working with Ext JS and parallel work with tasks on the client application, which is written in Backbone and ReactJs. I have something to compare.
This is one of many examples of a successful choice of technology for solving a specific problem. Writing business logic is what the customer expects from the developer and for which he is actually paid.
More often it happens like this - they take a trendy framework and spend a lot of time making friends with different plugins (for example, react-redux with react-router with react-router-redux), write the next component and upload it to the open source, write their cool 100500- th router or plugin under babel. And you can even make your own component
IF, Switch for JSX.
Everything is great, but if you look at it from the business side, it’s like the developer
himself creates a problem for himself , speaks at every corner about the complexity of solving it, and after a while
he heroically solves it , and the people watching him clap. Something like this.
Still back to the main topic.
I was the only person who wrote this system, and I was always tormented by the question: can a newbie on our project, who has never worked with Ext JS, deal with the system and how soon he can produce a result. After entering a new employee and briefing on the work on this project, the result was very decent. Fears were not justified.
4 years have passed since the beginning of the development of the administrative panel. There are new frameworks, techniques and approaches, the old ones are not fashionable, some are not very fashionable. A part of our functionality is no longer needed by the business, we rewrote a part of it for a long time, and a part of that code is still in production and it works and performs the same thing as before!
Conclusion 13: the code on Ext JS has passed the test of time.Results
Thanks to the various tasks that we had to face, I really liked the experience in development on Ext JS and it is incomparable with other experience on other frameworks. I really liked some architectural methods, approaches and beauty of the API. I even dreamed of implementing the same approaches on other frameworks myself (another bicycle).
Based on the foregoing, I concluded that Ext JS is great for solving the problem of building a complex administrative panel.
Please share in the comments, what tools and frameworks do you use to solve such problems, what difficulties have you encountered and how much time do you spend writing business logic?
Reader Bonuses

We give free access to three months of learning English through our online courses. To do this, simply follow the
link until December 31, 2017.

We will be glad to see you at the individual lessons of the course “English for IT-specialists”.
Complete a
free introductory lesson and get a comprehensive feedback on your level of knowledge, then choose a teacher and a training program for yourself!