1. #1
    Ext User jerrybrown5's Avatar
    Join Date
    Sep 2007
    Location
    Port St Lucie, FL
    Posts
    185
    Vote Rating
    0
    jerrybrown5 is on a distinguished road

      0  

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

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


    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:

    Code:
    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.

    Code:
    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); }
          }
        }
      }
    },

  2. #2
    Ext User jerrybrown5's Avatar
    Join Date
    Sep 2007
    Location
    Port St Lucie, FL
    Posts
    185
    Vote Rating
    0
    jerrybrown5 is on a distinguished road

      0  

    Default More Options from the (JSON) Fly

    More Options from the (JSON) Fly


    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.)

    Code:
       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

  3. #3
    Sencha - Architect Dev Team aconran's Avatar
    Join Date
    Mar 2007
    Posts
    9,091
    Vote Rating
    113
    aconran is a splendid one to behold aconran is a splendid one to behold aconran is a splendid one to behold aconran is a splendid one to behold aconran is a splendid one to behold aconran is a splendid one to behold aconran is a splendid one to behold

      0  

    Default


    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:
    Code:
    xtype:'tabpanel',
    listeners: {
       tabchange: function(){this.doLayout()}
    }
    There is no native facility built-in to do configuration changes between browsers.

    Aaron

  4. #4
    Ext User jerrybrown5's Avatar
    Join Date
    Sep 2007
    Location
    Port St Lucie, FL
    Posts
    185
    Vote Rating
    0
    jerrybrown5 is on a distinguished road

      0  

    Default


    Aaron,

    Quote Originally Posted by aconran View Post
    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.

    Code:
    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

  5. #5
    Sencha - Architect Dev Team aconran's Avatar
    Join Date
    Mar 2007
    Posts
    9,091
    Vote Rating
    113
    aconran is a splendid one to behold aconran is a splendid one to behold aconran is a splendid one to behold aconran is a splendid one to behold aconran is a splendid one to behold aconran is a splendid one to behold aconran is a splendid one to behold

      0  

    Default


    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

  6. #6
    Ext User jerrybrown5's Avatar
    Join Date
    Sep 2007
    Location
    Port St Lucie, FL
    Posts
    185
    Vote Rating
    0
    jerrybrown5 is on a distinguished road

      0  

    Default


    I noticed that when adding a button to a FormPanel the click event does not provide a way back to the parent form.

    Code:
     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.

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

  7. #7
    Ext User jerrybrown5's Avatar
    Join Date
    Sep 2007
    Location
    Port St Lucie, FL
    Posts
    185
    Vote Rating
    0
    jerrybrown5 is on a distinguished road

      0  

    Default


    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.
    Code:
    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
    Code:
    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
    Code:
    ...
     fields: ['url','name',{name:'shortName', mapping:0, convert:shortName }],
    ...

  8. #8
    Ext User jerrybrown5's Avatar
    Join Date
    Sep 2007
    Location
    Port St Lucie, FL
    Posts
    185
    Vote Rating
    0
    jerrybrown5 is on a distinguished road

      0  

    Default Web Site vs Web Application

    Web Site vs Web Application


    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

  9. #9
    Sencha Premium Member Troy Wolf's Avatar
    Join Date
    May 2007
    Location
    Kansas City
    Posts
    246
    Vote Rating
    2
    Troy Wolf is on a distinguished road

      0  

    Default


    Quote Originally Posted by jerrybrown5 View Post
    ...without leaving JSON
    You keep referring to doing things in JSON, or not "leaving JSON". Are you referring to object literals 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.

  10. #10
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,496
    Vote Rating
    44
    Animal has a spectacular aura about Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    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.