PDA

View Full Version : Tips from the Trenches: Building a Complex App w/ Ext 2.0 (Plugins, Updates Included)



jerrybrown5
12 Oct 2007, 12:18 AM
Updated Purpose:
I initially created this thread to submit a simple plugin to add some missing features; however, the nature of it has changed quite a bit since then. It sort of happened when a 'missing' feature that I tried to augment with my own was actually an undocumented native feature. I realized that perhaps that there is a void that some trench notes could fill. Perhaps I could make some notes that I would love to have read before embarking on my quest of Building a Complex App with Ext 2.0.

--- The first thread began here: ---

Jack and the rest of the programmers have done a great job with 2.0. A really nice new feature is the ability to create complex forms with only JSON code. However, when you need to do something a little bit more complicated such as setting events or overriding methods you have to resort to back to javascript objects. (That is bad.)

By adding this plugin:



Ext.ux.onConfig_plugin={
init:function(o){
if (o.onConfig && o.onConfig.overrideAdv){
for (var overrideName in o.onConfig.overrideAdv) {
var sMethod=o.onConfig.overrideAdv[overrideName].method;
var aArguments=o.onConfig.overrideAdv[overrideName].arguments;
if (!(aArguments instanceof Array)) { aArguments=[aArguments] };
o[overrideName]=o[overrideName][sMethod].apply(o[overrideName],aArguments);
}
}
};
if(typeof(o.onBrowser)==='object' && !(o.onBrowser instanceof Array)){
var found=false, foundDefaults=false ;
for (var variable in o.onBrowser) {
if (Ext[variable]){
Ext.apply(o,o.onBrowser[variable]);
foundDefaults=o.onBrowser[variable].defaults;
found=true; break;
}
}

if (!found && o.onBrowser.isElse ){
foundDefaults=o.onBrowser.isElse.defaults;
Ext.apply(o,o.onBrowser.isElse);
}

if (foundDefaults){/*because defaults are natively called prior to plugins..we have to re-run them ourself*/
o.items.each(function(f){
o.applyDefaults(f);
});
}
}
}
};



Update: Deprecated feature since native one exists. (See below)
Allows you to do this:

xtype:'tabpanel',
plugins:Ext.ux.onConfig_plugin,
onConfig:{
events: {
tabchange: function(){this.doLayout() }
}
},

And, voila...no external javascript objects required to set events. (This particular code also fixes a tab panel bug that occurs when a complex item (eg grid or layout container) does not properly render when it is not activated by the default.)

Logic can be used to remove an empty legend tag from a frameset, which causes an unsightly blank space.



xtype:'fieldset',
plugins:Ext.ux.onConfig_plugin,
onConfig:{
overrideAdv:{
onRender : {
method:'createSequence',
arguments:function(){
if (!this.title || this.title===""){ this.el.dom.removeChild(this.el.dom.firstChild); }
}
}
}
},

jerrybrown5
12 Oct 2007, 6:02 PM
Apparently not everything renders on IE as well as it should. (Maybe a few of you out there will agree with me on that point?!)

Here is my solution. With the following code and the updated plugin from my previous post, you can handle some browser handling issues while staying on JSON syntax. (That is a good thing.)



xtype:'tabpanel',
plugins:Ext.ux.onConfig_plugin,
onBrowser:{
isIE: {
defaults:{bodyStyle:'padding:5px', border: false, autoHeight:true}
},isElse: {
height:400,
defaults:{bodyStyle:'padding:5px', border: false, autoScroll:true}
}
},


Btw, this code fixes a bug where autoscroll on a tab panel with complex elements causes major rendering problems--IE users need to use auto height in this scenario.

This code is not limited to just IE. You can place any or all of the Ext[] variables there. (See here for the reference. http://extjs.com/deploy/dev/docs/?class=Ext) The isElse logic is hardcoded.


Best regards,
Jerry Brown

aconran
17 Oct 2007, 5:17 AM
You can already bind event handlers with a JSON configuration natively using ExtJS. Seems that this needs to be documented but all classes which inherit from Observable accept a config option of listeners.

Therefore to rewrite your initial example:


xtype:'tabpanel',
listeners: {
tabchange: function(){this.doLayout()}
}


There is no native facility built-in to do configuration changes between browsers.

Aaron

jerrybrown5
17 Oct 2007, 7:48 AM
Aaron,


You can already bind event handlers with a JSON configuration natively using ExtJS. Seems that this needs to be documented but all classes which inherit from Observable accept a config option of listeners.


Thanks, I missed that one; however, I see it now in the observable constructor.

Also, I wanted to point out a lesser used feature ( judging from the forum ) but equally powerful, Ext function prototypes. In this case, while still in JSON syntax you can use the createSequence function prototype to first call the normal onRender and then call the code to fix up the output, which is perfect syntax for quick tweaks of rendered content.



xtype:'fieldset',
plugins:Ext.ux.onConfig_plugin,
onConfig:{
overrideAdv:{
onRender : {
method:'createSequence',
arguments:function(){
if (!this.title || this.title===""){ this.el.dom.removeChild(this.el.dom.firstChild); }
}
}
}
},


Ext defines a few other function prototypes, and you can see them here. http://extjs.com/deploy/dev/docs/?class=Function

Best regards,
Jerry

PS. mmm humble pie tastes good :)

aconran
17 Oct 2007, 2:07 PM
Yes, the additional methods added to all functions are quite powerful. These functions make it easier to maintain scope and aid in aspect oriented programming.

Aaron

jerrybrown5
18 Oct 2007, 5:46 AM
I noticed that when adding a button to a FormPanel the click event does not provide a way back to the parent form.



Ext.Panel.prototype.addButtonOrig=Ext.Panel.prototype.addButton;
Ext.Panel.prototype.addButton=function () { b=this.addButtonOrig.apply(this, arguments); b.ownerCt=this; return b };


...allows you to do something no-brainer such as this without leaving JSON.



buttons: [{
text: 'Cancel',
listeners:{
click:function(){ this.ownerCt.hide() }
}
}]

jerrybrown5
18 Oct 2007, 7:46 PM
There is a powerful feature at the data.Field level for converting fields, convert. This feature is tied to the mapping property (where it can draw its value if it doesn't have one already). The ArrayReader implementation of this requires you to put the array index number of the mapped field as opposed to the field name. I think this is a needless limitation to an otherwise great feature so I updated it myself.

I consider this to be pseudo bug (missing feature) so here is the code to overwrite the base prototype.


Ext.data.ArrayReader.prototype.readRecords= function(o){
var sid = this.meta ? this.meta.id : null;
var recordType = this.recordType, fields = recordType.prototype.fields;
var records = [];
var root = o;
var map = {};
for(var j = 0, jlen = fields.length; j < jlen; j++){
var f = fields.items[j];
map[f.name]=j; /*value from this.map does not include the field index*/
}
for(var i = 0; i < root.length; i++){
var n = root;
var values = {};
var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
for(var j = 0, jlen = fields.length; j < jlen; j++){
var f = fields.items[j];
var m = (f.mapping !== undefined && f.mapping !== null);
var v;
if (m && n[f.mapping] !== undefined){
v=n[f.mapping];
}else if (m && n[map[f.mapping]] !== undefined){
v=n[map[f.mapping]];
}else if (n[j] !== undefined ){
v=n[j];
}else{
v=f.defaultValue;
}
values[f.name]=(f.convert ? f.convert(v) : v);
}
var record = new recordType(values, id);
record.json = n;
records[records.length] = record;
}
return {
records : records,
totalRecords : records.length
};
}



...allows you to do


function shortName(name){
if(name.length > 12){
return name.substr(0, 9) + '...';
}
return name;
};

var store=new Ext.data.SimpleStore({
fields: ['url','name',{name:'shortName', mapping: 'url', convert:shortName }],
inlineData : [['http://extjs.com/deploy/dev/examples/view/images/thumbs/up_to_something.jpg','name','shortName'],['http://extjs.com/deploy/dev/examples/view/images/thumbs/zack_dress.jpg','name','shortName'],['http://extjs.com/deploy/dev/examples/view/images/thumbs/zacks_grill.jpg','name','shortName'],['http://extjs.com/deploy/dev/examples/view/images/thumbs/up_to_something.jpg','name','shortName'],['http://extjs.com/deploy/dev/examples/view/images/thumbs/zack_dress.jpg','name','shortName'],['http://extjs.com/deploy/dev/examples/view/images/thumbs/zacks_grill.jpg','name','shortName'],['http://extjs.com/deploy/dev/examples/view/images/thumbs/up_to_something.jpg','name','shortName'],['http://extjs.com/deploy/dev/examples/view/images/thumbs/zack_dress.jpg','name','shortName'],['http://extjs.com/deploy/dev/examples/view/images/thumbs/zacks_grill.jpg','name','shortName'],['http://extjs.com/deploy/dev/examples/view/images/thumbs/up_to_something.jpg','name','shortName'],['http://extjs.com/deploy/dev/examples/view/images/thumbs/zack_dress.jpg','name','shortName'],['http://extjs.com/deploy/dev/examples/view/images/thumbs/zacks_grill.jpg','name','shortName']]
});



instead of


...
fields: ['url','name',{name:'shortName', mapping:0, convert:shortName }],
...

jerrybrown5
21 Oct 2007, 9:58 PM
A quick background about me. I have been programming professionally for the past 10 years across many platforms/languages including C++, Perl, Delphi, Visual Basic and of course JavaScript. In a 6 month period in 1999, I went on a certification spree and became MCSD, MCSE, CLP and A+ certified, none of which I have since maintained. In the past I did not believe in the open source (open information) movement but I have since become a convert.
---

Technologies between web sites and applications are converging. Up until recently there was order in the world of vertical market application development. The decisions that you had to make were relatively narrow. In the 'wonderful' Windows world of corporate America you would create the application part of your program in C++, Visual Basic or Delphi and make the standard looking corporate america program. And unless you wanted to go ISAPI or similar (and very few people did), you would have to switch technologies to your favorite web scripting language to program a consumer (website) module that exposes only a small subset of features.

These were the rules back then; however, they need not apply any more. The only differences that should exist between your website and the application interfaces are security priviliges. Application modules need the intuitiveness of websites and websites need the power of applications.

---

On this reply I am going to explore some of the big differences that still remain between web sites and web applications. A great programming platform will meet the needs of both use cases.

Web sites:
* A user will never have had training beforehand
* The user's technical skill level varies widely
* If a feature is not intuitive; it will not be used
* Everything is driven by a mouse (keyboard access is only required for handicapped users)
* Power end users crave for features, but they are often disappointed
* Back button is the most widely used button in the browser
* Must be usuable in all browsers or business will be lost
* Individual user sessions typically vary from 30 seconds to 20 minutes

Web applications:
* New employees are similar to web site users; Experienced employees have completely different requirements which are listed.
* The user will have become an expert in the portions of the software that they use.
* Users of similar roles are typically around the same technical skill level
* Focus on efficiency. Anything that saves time saves money. (The keyboard is almost always faster.)
* Can usually mandate a single browser in a corporate environment; however, multiple browser support is needed to facilitate remote users
* Typical user sessions can exceed 6 hours a day for a primary application

In my opinion, although I feel it is still the standout JavaScript user interface toolkit, Ext does leave some things to be desired:

1. Missing standard keyboard access on many controls including TabPanel, DataView, Toolbars.
2. Missing the glue the connects many of these high quality controls together. Although, great progress has been made on 2.0, much more in this area is needed.
a. A robust client side form repository feature would be nice.
b. More complex samples are needed. There should be atleast one sample that includes front to back (client to server side) code.
3. Some Grid speed issues.

In conclusion, even with these weaknesses, I believe Ext will become a standard tool for Web 2.0 applications for the following reasons:
1. The code that is developed is of very high quality and is highly customizable. It is a great foundation.
2. Ext is achieving critical mass in its user base
3. Features can be easily added/integrated by 3rd parties. My hook in to the Yahoo History component is a great example http://extjs.com/forum/showthread.php?t=15453, but there are many others including the grid filter plugin http://extjs.com/forum/showthread.php?t=14503. With a strong development community there is no stopping Ext.

Finally, I am not only a lifelong programmer but I am also a small business (travel software) owner. For my company it made sense on the business end as well. We have decided to use Ext as the key tool for all new programs because the relative low cost of a commerical and support license is well worth it to us. This means I can spend more time developing features which make my software unique and less on tedious cross browser user controls which will never be as good as what Ext offers today.

Best regards,
Jerry Brown

Troy Wolf
25 Oct 2007, 2:26 PM
...without leaving JSON
You keep referring to doing things in JSON, or not "leaving JSON". Are you referring to object literals (http://en.wikipedia.org/wiki/Object_literal) as JSON? I've never heard anyone call them JSON. I mean, the format is similar to JSON, but object literals are not literally JSON are they? (pun intended)

Btw, I really enjoy these types of conversations where we honestly and humbly seek to understand all that Ext offers, how to extend it, and best practices for programming in general. ~o)

Animal
27 Oct 2007, 5:12 AM
As I keep saying, "there's no such thing as JSON".

if you are writing in javascript, then you have javascript object literals.

"JSON" only exists on the wire. It's a data interchange format.

jerrybrown5
27 Oct 2007, 5:56 PM
It is very important to have the ability program a complete form in 'JSON-esque' (or whatever you want to call it) syntax since technical personnel at the non-programmer level can easily learn this format, whereas it will be much more difficult to teach them pure Javascript. Therefore, when properly used (including a client side form/data repository with matching server side features) this single feature has the ability to broaden the reach of Ext powered development. For example I plan on delegating new form creation to my web designer once the initial set is finished.

Best regards,
Jerry Brown

Animal
28 Oct 2007, 4:34 AM
I agree on offering a declarative approach to page authors who will not have the technical knowledge to hack javascript.

Writing huge object literals (even nesting a lot of already declared config objects) into the definition for a comples layout might still get a bit much in javascript object literal notation though.

I'm inclined to provide an analogue in JSP tags. The tags will nest in almost the same way as the javascript config objects.

Except that by using specific properties, and having the Java tag handling code understand about the javascript code it is expected to produce, and understand where it is in the nesting heirarchy, we can use much more intelligence to generate a very capable complete form, from a much simpler form of markup.

lshengjian
28 Oct 2007, 4:58 PM
I am EXT fans ,myname is alex.
your new demo desktop show us: how to create plugins application.
but I want load a plugin when I need,how to do?

bast regards!

jakeonthenet
2 Nov 2007, 1:18 PM
I think the term 'declarative javascript' would be more appropriate in describing the config object style of things. While JSON is javascript in form, it does really exist on the wire and/or server, and only has meaning off of the browser.

Both declarative javascript for UI design and JSON use object literal javascript as their underlying format.

How about EON (Ext Object Notation) as an acronym for the config object stuff?