Brand new to Ext JS 4.0 is a class Loader system that makes use of the new dependency system. These two powerful new features allow you to create extensive applications that allow the browser to download digest code as necessary.
Today, we’ll be looking at creating a small application that makes use of this new class Loader system, exercising the dependency management system. Along the way, we’ll discuss various configuration options for the Ext Loader system.
Learn the latest about Ext JS and HTML5/JavaScript for three intensive days with 60+ sessions, 3+ parties and more at SenchaCon 2013 . Register today!
Before we begin, we will fast forward into the future and peek at the results. Doing so will allow us to identify classes that we’ll need to extend.
Our simple app will contain two-way binding to a grid Panel and form Panels, respectively called UserGridPanel and UserFormPanel. The UserGridPanel will require the creation of a Model and a Store to support its operations. The UserGridPanel and UserFormPanel will be rendered in and managed by an extension to the Ext JS Window class known as UserEditorWindow. All of these classes will be under a namespace called MyApp.
Before we can begin with code, we’ll have to layout the directory structure. Here’s what the folder, organized by namespace, looks like.
As you can see with the illustration above, we have MyApp split according to namespace groupings or “packages.” In the end, our entire application will have an inter-dependency model that will function like the following illustration.
We’ll begin by filling out the contents of the index.html file, which sits at the root of our application and includes all that we’ll need to bootstrap our application.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <title>Ext 4 Loader</title> <link rel="stylesheet" type="text/css" href="js/ext-4.0.1/resources/css/ext-all.css" /> <script type="text/javascript" src="js/ext-4.0.1/ext-debug.js"></script> <script type="text/javascript" src="js/MyApp/app.js"></script> </head> </body> </html>
The index.html file contains the necessary link tag for the CSS file for Ext JS 4. This you’ve seen many times, but the inclusion of the ext-debug.js javascript file is something that might raise an eyebrow, as you’re probably used to including ext-all-debug.js for development and ext-all.js for production.
There are a few choices that Ext JS gives you out of the box, each with their own distinct advantages or disadvantages.
Here is a rundown of each of the files.
ext-all-debug-w-comments.js
ext-all-debug.js
ext-all.js
ext-debug.js
ext.js
ext-debug.js
.
Our index.html file made use of ext-debug.js, which is the bare minimum to get dynamic loading working. Later on, we’ll show you how you can use ext-all versions of the framework, allowing you to get the best of both worlds..
Since the UserGridPanel class requires a Model and data Store, we’ll have to develop those supporting classes first. We’ll begin by creating the Model and Store.
Ext.define('MyApp.models.UserModel', { extend : 'Ext.data.Model', fields : [ 'firstName', 'lastName', 'dob', 'userName' });
The above example contains code to extend Ext.data.Model, creating our UserModel class. By virtue of extending the data.Model class, Ext JS will dynamically load it for us and then create the UserModel class after it and the dependencies for data.Model have loaded.
Next, we’ll create the UserStore class, an extension to Ext.data.Store.
Ext.define('MyApp.stores.UserStore', { extend : 'Ext.data.Store', singleton : true, requires : ['MyApp.models.UserModel'], model : 'MyApp.models.UserModel', constructor : function() { this.callParent(arguments); this.loadData([ firstName : 'Louis', lastName : 'Dobbs', dob : '12/21/34', userName : 'ldobbs' firstName : 'Sam', lastName : 'Hart', dob : '03/23/54', userName : 'shart' firstName : 'Nancy', lastName : 'Garcia', dob : '01/18/24', userName : 'ngarcia' ]); });
When creating our singleton UserStore class, we add a new requires key to the UserStore prototype. The requires key is a list that instructs Ext JS to fetch any required classes before our class is instantiated. In this case, we list our UserModel class as a required class.
By virtue of our UserModel class being defined in our store’s model property, Ext JS will load it automatically. It is my opinion that listing the class in the requires key allows your code to be self-documenting, reminding you that the UserModel class is required.
OK. We have our foundation classes created for the views.UserGridPanel, which means we can move on and create the UserGridPanel itself.
Ext.define('MyApp.views.UsersGridPanel', { extend : 'Ext.grid.Panel', alias : 'widget.UsersGridPanel', requires : ['MyApp.stores.UserStore'], initComponent : function() { this.store = MyApp.stores.UserStore; this.columns = this.buildColumns(); this.callParent(); buildColumns : function() { return [ header : 'First Name', dataIndex : 'firstName', width : 70 header : 'Last Name', dataIndex : 'lastName', width : 70 header : 'DOB', dataIndex : 'dob', width : 70 header : 'Login', dataIndex : 'userName', width : 70 });
When looking at the above code, keep a keen eye on the requires key. Notice how we added the UserStore as a required class. We just configured a direct dependency relationship between our grid Panel extension and our own data Store extension.
Next, we’ll create the form Panel extension.
Ext.define('MyApp.views.UserFormPanel', { extend : 'Ext.form.Panel', alias : 'widget.UserFormPanel', bodyStyle : 'padding: 10px; background-color: #DCE5F0;' + ' border-left: none;', defaultType : 'textfield', defaults : { anchor : '-10', labelWidth : 70 initComponent : function() { this.items = this.buildItems(); this.callParent(); buildItems : function() { return [ fieldLabel : 'First Name', name : 'firstName' fieldLabel : 'Last Name', name : 'lastName' fieldLabel : 'DOB', name : 'dob' fieldLabel : 'User Name', name : 'userName' });
Because our UserForm class does not technically require any of the classes we’ve developed thus far, we don’t need to add a requires directive.
We’re almost done. We need to create the UserEditorWindow class and then apps.js, which will launch our application. The code for the UserEditorWindow class is below. The class is pretty lengthy because it contains the code for the grid to form panel binding, so please bear with me on this.
Ext.define('MyApp.views.UserEditorWindow', { extend : 'Ext.Window', requires : ['MyApp.views.UsersGridPanel','MyApp.views.UserFormPanel'], height : 200, width : 550, border : false, layout : { type : 'hbox', align : 'stretch' initComponent : function() { this.items = this.buildItems(); this.buttons = this.buildButtons(); this.callParent(); this.on('afterrender', this.onAfterRenderLoadForm, this); buildItems : function() { return [ xtype : 'UsersGridPanel', width : 280, itemId : 'userGrid', listeners : { scope : this, itemclick : this.onGridItemClick xtype : 'UserFormPanel', itemId : 'userForm', flex : 1 buildButtons : function() { return [ text : 'Save', scope : this, handler : this.onSaveBtn text : 'New', scope : this, handler : this.onNewBtn onGridItemClick : function(view, record) { var formPanel = this.getComponent('userForm'); formPanel.loadRecord(record) onSaveBtn : function() { var gridPanel = this.getComponent('userGrid'), gridStore = gridPanel.getStore(), formPanel = this.getComponent('userForm'), basicForm = formPanel.getForm(), currentRec = basicForm.getRecord(), formData = basicForm.getValues(), storeIndex = gridStore.indexOf(currentRec), key; //loop through the record and set values currentRec.beginEdit(); for (key in formData) { currentRec.set(key, formData[key]); currentRec.endEdit(); currentRec.commit(); // Add and select if (storeIndex == -1) { gridStore.add(currentRec); gridPanel.getSelectionModel().select(currentRec) onNewBtn : function() { var gridPanel = this.getComponent('userGrid'), formPanel = this.getComponent('userForm'), newModel = Ext.ModelManager.create({}, 'MyApp.models.UserModel'); gridPanel.getSelectionModel().clearSelections(); formPanel.getForm().loadRecord(newModel) onAfterRenderLoadForm : function() { this.onNewBtn(); });
The code for our UserEditorWindow contains a lot of stuff to manage the full binding lifecycle of the UserGridPanel and UserFormPanel classes. In order to instruct Ext JS to load the two classes we created earlier, we have to list them in the requires list.
We’re now ready to tie this all together in the app.js file. To maximize our learning, we’ll be making three passes at this. We’ll begin with the simplest configuration first, and add more as we progress.
Ext.Loader.setPath('MyApp', 'js/MyApp'); Ext.onReady(function() { Ext.create('MyApp.views.UserEditorWindow').show(); });
Initially, our app.js file instructs Ext JS to add a path for the MyApp namespace. We do this via the Ext.loader.setPath call, passing in the namespace as the first argument, and the relative path to the page being loaded.
Next, we call Ext.onReady, passing in an anonymous function, which contains a call to Ext.create. Ext.create is responsible for lazy instantiating classes with Ext JS 4.0. We pass in the String representation of our UserEditorWindow class to be instantiated. Since we don’t need a reference to the instance of our class and want to show it immediately, we chain a show method call.
If we view this in our page ( http://moduscreate.com/senchaarticles/01/pass1.html ), we see that the UI renders, but it’s pretty slow and we get a warning message inside of FireBug from Ext JS!
Ext JS barks at us because we’re not using the Loader system in the most optimized way. We’ll revisit this issue in a second. However, this is a great learning opportunity that we should capitalize on!
I’ve configured my FireBug instance to display XHR requests inside of the console, which allows me to see all such requests without having to switch to the Net tab. This gives us chance to filter though all of the Ext JS classes loaded, to watch the class dependency system work, as we’ve instructed it to do!
Simply type in “User” in the FireBug console filter and you’ll see how it all comes together.
As we can see, the UserEditorWindow class is first loaded, which requires the UserGridPanel. The UserGridPanel requires the UserStore and UserModel classes. Lastly, the UserFormPanel class is loaded.
I mentioned earlier that Ext JS barked because we’re not using the Loader system in the most optimized way. This is because dependencies identified after Ext.onReady has fired are loaded via synchronous XHR , which is not the most efficient way and is not easy to debug at all.
To remedy this issue, we’ll have to modify app.js to instruct Ext JS to load our classes in a way that is both performant and easier to debug
Ext.Loader.setPath('MyApp', 'js/MyApp'); Ext.require('MyApp.views.UserEditorWindow'); Ext.onReady(function() { Ext.create('MyApp.views.UserEditorWindow').show(); });
To enable faster loading of our classes and afford a better debugging experience, we simply have to add a call to Ext.require above our Ext.onReady, instructing Ext JS to require our UserEditorWindow class. Doing this allows Ext JS to inject script tags to the HEAD of the document, allowing resources to load before Ext.onReady fires.
Visit http://moduscreate.com/senchaarticles/01/pass2.html to see this working. After loading the page, you’ll notice that Ext JS will no longer fire warning messages to the console.
What we’ve done is enable lazy loading of Ext JS framework and our application classes. While this is the best for debugging, the page render times can be very painful for rapid debugging sessions. Why – you ask?
The simple answer is that the number of resources loaded is immense. In our example, Ext JS makes 193 total requests to the web server for JavaScript resources, most of which are cached.
We created six JavaScript files (five classes and app.js). That means that to load the required Ext JS files, the browser had to make 187 requests. This solution is viable but not ideal for many and works best when you’re developing in a local dev environment.
To remedy this issue, we can create a hybrid situation, where we load the entire framework via ext-all-debug and then load our classes dynamically. To do this, we’ll need to modify two files.
First, we’ll need to modify our index.html to include ext-all-debug.js instead of ext-debug.js
<script type="text/javascript" src="js/ext-4.0.1/ext-all-debug.js"></script>
Next, we’ll need to modify app.js to enable Ext Loader.
(function() { Ext.Loader.setConfig({ enabled : true, paths : { MyApp : 'js/MyApp' }); Ext.require('MyApp.views.UserEditorWindow'); Ext.onReady(function() { Ext.create('MyApp.views.UserEditorWindow').show(); }); })();
We enable Ext Loader by calling Loader.setConfig, passing in an anonymous object, which has its enabled property set to true and our namespace set to path mapping.
By modifying our app.js file, we allowed our application to load and render in just over a second in a local dev environment
And there you have it! We created a simple application allowing us to use the new Ext JS class dependency system as well as Loader. You may download these lab files via http://moduscreate.com/senchaarticles/01/files.zip .
The Ext Loader functionality is indeed very useful. I use it in a larger MVC application. However, there are some caveats. One of which is that you do not only want to load Controllers, Views, Models and Stores, but you also would like to load small components or widgets that can be reused throughout your application. I find it difficult to figure out how to implement that and fit in the overall application architecture.
A second (small) detail is, that if you use controllers and you have a model named UserModel, the controller will create a getter getUserModelModel, likewise a UserStore becomes a getUserStoreStore. Small but annoying detail.
I still am looking forward to learn from a ‘real’ application with multiple controllers (possibly a HMVC structure), reusable widgets and components that can be used in multiple views, a strict separation of concerns between control logic, view logic, query logic (I mean the proxy) and model logic.
So, I am looking forward to your Ext Js 4.0 in Action.
Excellent article!! I’ve yet to really start playing with ExtJS4 but I am so looking forward to it.
You know, that was actually pretty well-written and easy to understand. That class loader system is something I would’ve killed to have had years ago.
Echoing what halcwb said about taking this to a larger App context. Why not go the user guide way and call app.launch() – and include controllers… I think examples like these will confuse many users who need to learn Best Practices of building a full blown app. If all they need is a modal window they should just use JQuery or some microjs framework.
Also did you notice it takes 7 seconds to load your page? It’s cause every class is loaded separately in 203 Requests! An SDK builder is required here, or just go the ext-all option, it will be faster.
@DB and @halcwb This article was written with the novice in mind and is over ten pages printed! There was no way I was going to mix MVC in the mix. The purpose was to show how to use Ext.Loader with custom classes. I believe it paves the way for future articles that describe what you’re looking for. That is, if Sencha will have me do it :)
I can see the usefulness of this approach when the number of files is small or when working in a development mode, but does JSBuilder (if Ext’s still using that to build) read these Ext.require() statements to build a single JS bundle for production deployments?
@Trung,
I believe it’s a missing piece to Ext Loader. Something that I’ve talked about since #ExtJS 4.0’s launch.
I know this is a post on the Class Loader, not really Ext application architecture, but how would you go about using an App.js file when you have a multi-page site. That is, you have a /users page and a /products page and each essentially has its own Ext.onReady – obviously you can’t include two calls to Ext.onReady in App.js and it seems hacky to do a conditional check based on the URL to determine what Ext.onReady to fire. Would the recommended best practice solution to treat each page (i.e. each /users and /products) as its own App (i.e. UsersApp.js and ProductsApp.js) which could then be merged into an App.js for performance?
Why do you need to use initComponent to set the items of the form panel? Can’t you just use the items config option?
Very very good article man, I learned EXT JS 3.0 but now I want to learn the 4 version as soon as possible jajaja
Greatings from Chihuahua
One thing that is missing is how to use the “package” files. That is, using package-grid.js instead of all the files separately that make up the grid. It is the cross between ext-all and individual files. They used to make these files for us in the Ext3 days, but Ext4’s loader is the way to actually do it…
Can the Loader resolve multipart namespaces? Eg, if you specify:
Ext.Loader.setConfig({
paths: ‘top: ‘src/top’
Will it be able to load the class ‘top.middle.Bottom’ from ‘src/top/middle/Bottom.js’ ?
I guess I could try, but I’m lazy :p
@bigfish, i think : paths : { ‘myNamespace’ : ‘src/mynamespace’, ‘othernamespace’ : ‘src/othernamespace’ }
>>> I believe it’s a missing piece to Ext Loader. Something that I’ve talked about since #ExtJS 4.0’s launch.
Can you explore this some more with your friends at Sencha? When are they planning to add the ability to combine the Ext-loaded files into a single file? This is a must have feature for larger apps.
The Sencha command-line tool in the SDK builds a Jsb and creates a single js file of all the required classes.
I use that when going from dev to deploy.
In object oriented terms the example code is declaring derived class types when instances of the core ExtJS class would be sufficient. Does the class loader mandate this form of OO design?
First, I greatly appreciate your post. This is the most useful tutorial I have found on any aspect of Ext JS 4 to date. Thank you so much for providing it.
” I believe it paves the way for future articles that describe what you’re looking for. That is, if Sencha will have me do it ” : They’d better!
“@DB and @halcwb This article was written with the novice in mind and is over ten pages printed! There was no way I was going to mix MVC in the mix. The purpose was to show how to use Ext.Loader with custom classes. ”
I completely appreciate your perspective here. However, I feel that ALL that’s been published to date is mini-examples that describe little scenarios. There are literally tons of them in the docs, the guides, the samples, this blog etc. There are so many that describe just one little aspect without a view on the whole. THESE are what are confusing us. Each one is in a silo, configs objects differently (see quote below), introduces concepts never seen elsewhere with little explanation, etc.
“Why do you need to use initComponent to set the items of the form panel? Can’t you just use the items config option?”
Sencha has done a very poor job of introducing us all the Ext JS 4. I for one am quite disappointed. I convinced my management team that Ext was the way to go for our future development needs. Now, I am struggling to complete a complex app because of the lack of a single coherent example more complex than editing a user in a grid via a form.
Sencha needs to step up and provide a well documented single MVC example that incorporates and explains all best practicies.
basicForm.updateRecord(currentRec);
It’s hard to find a good explanation about these.
@JustinNoel is on the money, as soon as I step outside of the example and into the real world, shit does not stack up at all :(
The desktop app is nice, the feed viewer app is nice too. Even doing the Google music beta interface ( http://img823.imageshack.us/img823/3433/googlemusicbeta.png ) in extjs is fairly straight forward as each one of these things are straight forward due to their single use/purpose.
Real business apps are not single use/purpose, they have all sorts of data that interact all over the place depending on a ton of criteria (our app, attempting to capture who has access to what is convulted as there is more than one thing happening)
I’d like to see an example app that has different data going on, different views depending on different situations, even a standard shopping site with front and back ends is simple/straight forward.
I guess the issue is real world examples are only going to exist in real world contexts and as such are probably not going to be opened up as examples to follow as they actually solve business needs, which are not for general public consumption… This is very much the case with out app. I know exactly how I want to work and which extjs bits to use, I’m just struggling to structure this app so it is not a hodge podge of fail…
@Nicholas Orr @Justin Noel It seems like you guys have grasped the basics of ExtJS but not the basics of JavaScript…. All ExtJS is, is JavaScript….if you are unsure of how to create new Elements or Widgets via JS/ExtJS then maybe you should be looking for more of a JavaScript course.
Creating a large application just adds more widgets and lines of code, this is done by creating objects/methods via JavaScript and calling those via Events/handlers. Sure along with a large application comes much more code to manage and how do you manage that? Well that comes with experience and guidance.
@Donald – I never suggested I was having trouble creating widgets or elements, nor am I a complete noob to JavaScript. Ext JS 4 is a very complex framework, has a completely new MVC structure, etc. That is slightly beyond “looking for more of a JavaScript course”
So, if CakePHP, RoR, or any other framework came out with a complete rewrite and did not provide a working example that covered MOST aspects in a single coherent example, should the confused programmer simply “look for a PHP course” or “look for a Ruby course”?
There is no doubt that much more experienced developers are well on their way to productivity with Ext JS. However, the less experienced (to Ext) are baffled. Look in the forums for people begging for a complete CRUD example, a better MVC example. Should we all be taking “JavaScript for Dummies” instead? Sencha has certainly not provided enough truly useful examples to encourage people to adopt Ext JS.
@Justin Noel Maybe this hasnt been mentioned anywhere but you dont have to follow their MVC pattern…You can still use ExtJS as you would with version 3 or 2……
@Donald except Ext doesn’t come across as vanilla JS… the devs have put a fair amount of thought into how to structure things and with that in mind the came up ExtJS. The bite sized examples work really well as long as you use the example stand alone. I can put together a grid with a json store that when a row is clicked it loads up a form and save the data to and from the server. This is a one pager, single function.
Going from that to an App that has lots of stuff going on needs some sort of structure and this isn’t really clear how best to do this in ExtJS… Maybe I haven’t read enough.
I get that we don’t have to use the MVC deal. It doesn’t really fit what I want to do anyways, same as how the RoR MVC way didn’t fit what I wanted to do either…
@Justin Noel. Thank you for spelling it out. This is exactly the reason why I have trouble to adopt ExtJS for my purposes. My gut feeling tells me that ExtJS is the way to go. I have no trouble incorporating individual pieces, but simply cannot jump that final, but crucial hurdle. One less paying customer (that would be me) for Sencha until I can see a best practice example of a proper ‘real world app’ as Justin described. It doesn’t have to be huge or complicated, but it should contain ALL the parts required to do it and hints regarding how it can be extended.
to realize namespaces?
Cause tried something like this
Ext.Loader.setPath(‘incbszdb’, ‘static/js’);
->views/->controller/
and the app said “Namespace not found…”
I don’t quite understand why I would want the loader involved in much of anything. If we are wanting to load our app and then just swap data back and forth – then why not load it all at once?…..if the loader wasn’t so slow….well maybe…..but….damn……it’s……s…..lo…….w……..
I absolutely agree about the need for more MVC examples. I chuckle when I see guys who can’t provide an MVC example belittle someone who is simply asking for an example. I mean…..what’s all the hype about the latest greatest MVC pattern to be used with extjs4 if not even the wizards can provide a working example?
https://github.com/lucassus/extjs4-account-manager
Look at the above link for a full CRUD/mvc example with code that works. It’s basic….and it looks like the guy just finished the unfinished non-working example from the API docs…..but it works……..and it’s rails specific…..for those of us from a rails background.
I’ve been trying to adapt his pattern to a dual-grid example where a child grid loads records based on parent record chosen in parent grid. As soon as I’ve got it working I’ll put in on github and post it back to the forums.
Wish there were more examples out there……..but I guess examples will have to be provided by the community.
Can the Loader System load user css files? If it can, would you please give some sample code?
Thanks and Best Regards!
I complained above about the lack of an MVC CRUD example. I’ve know posted my own example. It might not be any good, but it is at least a starting point.
I’d love feedback on it.
https://www.sencha.com/forum/showthread.php?139433-Ext-MVC-CRUD-Demo&p=622323
Its giving weird results when it is integrate ExtJs 4 with share point webpart.How to over come from these problem?
2.How to overide Extjs4 CSS to Sharepoint CSS dynamically? please help
Hi Jay or anyone that may know,
When I read this post, I feel everything was cristal clear — excellent work. So I decided to use the codes here and try to make it loaded by the EXT demo portal. In other words, I tried to make your ‘UserEditorWindow’ show as a portlet on the EXT JS 4 demo portal.
After I put everything together, and changed the demo portal’s “portlet-3” to load content as
items: [Ext.create(‘MyApp.views.UserEditorWindow’)],
The portlet bar was shown on the portal, but had no content,
Could you please let me know if this should work with portal as well, and if so, how?
Thanks
Could you explain what ‘digest code’ is, as in the second sentence of the article: ‘These two powerful new features allow you to create extensive applications that allow the browser to download digest code as necessary.’
Aw, this wwas an incredibly good post. Finding the time and actual effort to create a top notch
article… but whaat can I say… I hesitate a whole lot and never manage to
get anything done.
very old, the only thing i could found on google about this question.
time to change some modern JS like REACT, VUE