Page 1 of 12 12311 ... LastLast
Results 1 to 10 of 120

Thread: application design, component creation and efficiency

  1. #1
    Ext User
    Join Date
    Jan 2008
    Posts
    103
    Vote Rating
    0
      0  

    Default application design, component creation and efficiency

    I'm rather new to Ext, and advanced JavaScript use. I've mainly used JavaScript sparingly to manually validate HTML forms, or do some other simple action. As for my programming experience, I've been using PHP for a while, and recently made the jump to PHP5, requiring a better understanding of true OOP, although I've read that PHP5 is not quite there.

    I hate to beat the application design 'dead horse' here, although I think the horse is still limping along. Perhaps I'm not looking in the right place. I've read through the following forum posts so far, which cover or touch on the issue of app design:

    Advice needed on structuring application code
    Variable Placement? Controlling Memory Usage.
    Application Design Patterns

    Besides the forum, I also read the "Application Layout for Beginners" in the manual.

    I'm creating an application that will run on an intranet. I'll be using PHP5 in the backend with the Zend Framework, and Ext for the frontend, effectively replacing the 'View' of the Zend Frameworks MVC concept. The PHP backend will simply dish out data in the proper format to Ext as requested. But how I should design the Ext part of the application is still a mystery to me.

    While I understand the Module Pattern concept, I'm still not sure how to properly lay everything out in my application. For instance, I have the following code in my test app:

    test.js

    Code:
    // create namespace
    Ext.namespace('TEST');
    
    // create a data module
    TEST.data = function() {
    
    	// test grid data
    	var gridData = [
    		['9/1 12:00am', 'chughes', 'testing'],
    		['9/2 12:00am', 'ksmith', '1..2..3...'],
    		['9/3 12:00am', 'pjames', 'hello'],
    		['9/4 12:00am', 'ajones', 'another test'],
    		['9/5 12:00am', 'pkramer', 'data'],
    		['9/6 12:00am', 'rsmith', 'more data']
    	];
    
    	return {
    
    		storeGridData: new Ext.data.SimpleStore({
    			fields: [
    				{name: 'created', type: 'date', dateFormat: 'n/j h:ia'},
    				{name: 'author'},
    				{name: 'subject'}
    			]
    		}),
    
    		loadGridData: function() {
    			this.storeGridData.loadData(gridData);
    		}
    
    	};
    
    }();
    
    // create a panels module
    TEST.panels = function() {
    
    	return {
    
    		panelAccordionNavigation: {
    			title:'Navigation',
    			html:'nav goes here',
    			border:false
    		},
    
    		panelAccordionSettings: {
    			title:'Settings',
    			html:'settings go here',
    			border:false
    		},
    
    		panelTabWelcome: {
    			html:'<p>This is a welcome tab.</p>',
    			title: 'Welcome',
    			style:'padding:10px',
    			autoScroll:true
    		},
    
    		panelTabAnother: {
    			title: 'Another Tab',
    			html: '<p>This is another tab.</p>',
    			autoScroll:true,
    			closable:true
    		},
    
    		panelTabGrid: new Ext.Panel({
    			title: 'Grid Tab',
    			autoScroll:true,
    			closable:true,
    			listeners: {
    				'activate': function(p) {
    					TEST.data.loadGridData();
    					p.doLayout();
    				},
    				single:true
    			}
    		}),
    
    		gridpanelTickets: new Ext.grid.GridPanel({
    			store: TEST.data.storeGridData,
    			columns: [
    				{header: "Created", width: 75, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'created'},
    				{header: "Author", width: 75, sortable: true, dataIndex: 'author'},
    				{id: 'Subject', header: "Subject", sortable: false, dataIndex: 'subject'}
    			],
    			stripeRows: true,
    			autoExpandColumn: 'Subject',
    			border:false,
    			autoHeight:true
    		}),
    
    		tabpanelMain: new Ext.TabPanel({
    			border:false,
    			activeTab:0
    		}),
    
    		init: function() {
    			this.panelTabGrid.add(this.gridpanelTickets);
    			this.tabpanelMain.add(this.panelTabWelcome);
    			this.tabpanelMain.add(this.panelTabAnother);
    			this.tabpanelMain.add(this.panelTabGrid);
    		}
    
    	};
    
    }();
    
    // create a layout module
    TEST.layout = function() {
    
    	return {
    
    		// setup the north region
    		regionNorth: {
    			region:'north',
    			html: 'North',
    			border: false,
    			baseCls: 'x-plain',
    			height: 75,
    			margins:'5 5 0 5'
    		},
    		// setup the east region
    		regionEast: {
    			region:'east',
    			html:'east side',
    			title: 'East',
    			width:200,
    			margins:'5 5 0 0'
    		},
    		regionSouth: {
    			region:'south',
    			html:'south side',
    			title: 'South',
    			collapsible:true,
    			minHeight:100,
    			maxHeight:200,
    			height:100,
    			split:true,
    			margins:'0 5 5 5'
    		},
    		regionCenter: {
    			region:'center',
    			layout: 'fit',
    			margins:'5 5 0 5',
    			items: TEST.panels.tabpanelMain
    		},
    		regionWest: {
    			region:'west',
    			title: 'Navigation',
    			width:150,
    			margins:'5 0 0 5',
    			layout:'accordion',
    			layoutConfig:{
    				animate:true
    			},
    			items: [
    					TEST.panels.panelAccordionNavigation,
    					TEST.panels.panelAccordionSettings
    			]
    		},		
    		
    		// render the main application layout
    		renderMainLayout: function() {
    
    			// init the panels module
    			TEST.panels.init();
    
    			new Ext.Viewport({
    
    				layout: 'border',
    				items: [
    					this.regionNorth,
    					this.regionEast,
    					this.regionWest,
    					this.regionSouth,
    					this.regionCenter
    				]
    
    			});
    
    		}
    
    	};
    
    }();
     
    // create application module
    TEST.app = function() {
    
        return {
     
            // init method
            init: function() {
    
    	// render the main layout
    	TEST.layout.renderMainLayout();
    
            }
        };
    }(); // end of app
     
    // end of file
    As you can see, I define all of my panels in the 'panels' module, all of the regions get defined in the 'layout' module, and then my app renders the layout. I ran into a few snags with this design. For instance, creating a TabPanel with an array of 'items' of pre-defined object configs doesn't work and throws a couple of errors. Instead, I must use the TabPanel's add() function to add the panels. Also, if a panel has nested components (such as a GridPanel in my case), it must be defined as a component (new Ext.Panel), as you can see in 'panelTabGrid' in the above code, in order to be able to add components using the add() method.

    I'm not sure why the array of pre-defined item configs in a TabPanel throws an error, but not a Panel with an 'accordion' layout. (see above code: 'regionWest' in the layout module) I can only assume that I just don't know what's happening in the background.

    Enough with my problems and on to the issue at hand. Is this design a good one, or has someone come up with something better?

    As for components creation goes, should I define all of my components in a JavaScript file as a module and make calls to them as needed? Or, should I just 'serve' the components to Ext with PHP using Ajax?

    And, one final question pertaining to efficiency(whew): Does defining a new component as an actual component (new Ext.Component) create a bigger overhead than a simple JSON config?

    Thanks so much.

  2. #2
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    8
      0  

    Default

    Thanks for posting this. I'm in very similar boat. I've been learning from the ext examples/demos which kind of have a procedural vs. OOP flavor I think. I was just about to post a very similar thread.

    In addition to your questions I was also wondering about private properties. For the most part I've noticed most of the properties you've created are public. The only private property I noticed was the underlying data. So, my question is, what would be considered good practice for determining what should be public vs. private?

    As I convert my "procedural" example code I have been working with to OOP style like you have, I almost find it a chore to deal with the scope when anything is private. So as I hack through the code I'm left wondering why make anything private?

    These are not "classes" per se correct? So is there really any issues with worring about making things private so they are not inherited or however that whole inheritance thing works?

    Edit: One other issue that's been in the back of my mind is how to deal with file structure. That is, with all of these modules do you develop individual js files for each module or lump them into one file? For example I see that ext/source breaks up the files into modules. And then there's ext_all.js which I presume is basically a synthesis of the individual source files. I've read that web pages serve up quicker with fewer/bigger files than more/smaller files. So, if all of that is correct, is there some utility that helps to combine your files once you go from development to production?

  3. #3
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,664
    Vote Rating
    403
      0  

    Default Application Design Based On Pre-Configured Classes

    I successfully use Ext.App (with slightly modified init process) from ext/examples/desktop for a huge application I write currently. I follow the following rules while writing:
    1. Use lazy instantiation (xtype) as much as possible.
    2. Use pre-configured classes (I'll explain later).
    3. Implement relations on parent level.
    4. Keep each class in its own file while developing, concat and minify for production.



    1. Use lazy instantiation (xtype) as much as possible.


    The point here is that if you use xtypes the real Ext objects they represent are not even created until they are needed. We've already got used to lazy rendering (render only when needed) but Ext 2 makes a step forward: xtype = if you will need this object then this is how it will be created.


    2. Use pre-configured classes.

    xtype approach described in point 1. is only possible if you have "pre-configured classes" what are extensions of Ext classes with configuration options applied and/or with added functionality. For example, I use the following code for gender selection combo:
    PHP Code:
    // vim: ts=4:sw=4:nu:fdc=2:nospell
    /**
      * Ext.ux.GenderCombo Extension Class for Ext 2.x Library
      *
      * @author  Ing. Jozef Sakalos
      * @version $Id: Ext.ux.GenderCombo.js 703 2008-02-10 22:19:03Z jozo $
      *
      * @class Ext.ux.GenderCombo
      * @extends Ext.ux.IconCombo
      */
    Ext.ux.GenderCombo Ext.extend(Ext.ux.IconCombo, {
        
    // defaults
         
    genderFemaleCls:'ux-icon-gender-female'
        
    ,genderFemaleText:'Female'
        
    ,genderMaleCls:'ux-icon-gender-male'
        
    ,genderMaleText:'Male'
        
    ,genderUnknownCls:'ux-icon-gender-no'
        
    ,genderUnknownText:'---'
        
    ,valueField:'genderValue'
        
    ,displayField:'genderText'
        
    ,iconClsField:'genderCls'
        
    ,mode:'local'
        
    ,triggerAction:'all'
        
    ,editable:false
        
    ,forceSelection:true

        
    ,initComponent:function() {

            
    Ext.apply(this, {
                
    store: new Ext.data.SimpleStore({
                     
    id:0
                    
    ,fields:[{name:'genderValue'type:'int'}, 'genderText''genderCls']
                    ,
    data:[
                         [
    2this.genderUnknownTextthis.genderUnknownCls]
                        ,[
    0this.genderMaleTextthis.genderMaleCls]
                        ,[
    1this.genderFemaleTextthis.genderFemaleCls]
                    ]
                })
            });

            
    // call parent initComponent
            
    Ext.ux.GenderCombo.superclass.initComponent.call(this);

        } 
    // eo function initComponent

        // grid support
        // {{{
        
    ,renderGender:function() {
            return function(
    val) {
                var 
    retval;
                var 
    gp Ext.ux.GenderCombo.prototype;
                switch(
    val) {
                    case 
    0// male
                        
    retval '<div class="ux-cell-gender ux-icon-gender-male">' gp.genderMaleText '</div>';
                    break;

                    case 
    1// female
                        
    retval '<div class="ux-cell-gender ux-icon-gender-female">' gp.genderFemaleText '</div>';
                    break;

                    default: 
    // all others, usually 2
                        
    retval '<div class="ux-cell-gender ux-icon-gender-no">' gp.genderUnknownText '</div>';
                    break;
                }
                return 
    retval;
            };

        } 
    // eo function renderGender
        // }}}
        // {{{
        
    ,editorGender:function() {
            return new 
    Ext.grid.GridEditor(new Ext.ux.GenderCombo());
        } 
    // eo function editorGender
        // }}}

    });

    // register xtype
    Ext.reg('gendercombo'Ext.ux.GenderCombo);

    // eof 
    General extension pattern for pre-configured classes I use is:
    PHP Code:
    MyScope Ext.extend(Ext.form.ComboBox, {
        
    // configurables
        // anything what is here can be configured from outside
         
    border:false

        
    // {{{
        
    ,initComponent:function() {
            
    // {{{
            
    Ext.apply(this, {
                
    // anything here, e.g. items, tools or buttons arrays,
                // cannot be changed from outside
            
    }); // e/o apply
            // }}}

            // call parent
            
    MyScope.superclass.initComponent.apply(thisarguments);

            
    // after parent code here, e.g. install event handlers

        
    // e/o function initComponent
        // }}}
        // {{{
        
    ,onRender:function() {

            
    // before parent code

            // call parent
            
    MyScope.superclass.onRender.apply(thisarguments);

            
    // after parent code, e.g. install event handlers on rendered components
            
        
    // e/o function onRender
        // }}}
        
        // any other added/overrided methods

    }); // e/o extend

    // register xtype
    Ext.reg('mycomponentxtype'MyScope); 
    3. Implement relations on parent level.

    Imagine you have a border layout with grid in west and form in center. Selecting a grid row should display values in form. Now, where to put logic of that? To grid or to form? Neither of them. Grid doesn't know that form exists and form doesn't know that grid exists. The component that is aware of both of them is their common parent (viewport or window).

    Therefore, the relations have to be established at the parent level, e.g. window. Code there listens to grid's events and loads form data on selection change and on form submit event it updates grid record.

    If I'd put this code to grid the grid cannot exist w/o form, if to form, form cannot exist w/o grid. Got the idea?


    4. Keep each class in its own file while developing, concat and minify for production.


    Yes, this is Ext approach. I just take all files I include in the header of devel page, concat 'em (in the original order) to one file, minify the result and I have production version.


    A final advice: Don't speculate too much about application structure, layout, various controllers, loaders, interfaces, whatever too much. Write good re-usable pre-configured classes instead and put them somehow together in the first place. If they are really good and re-usable you can change your app layout, use a different approach and your classes will still work. Like Lego - if you have blocks you can build a castle in minutes.
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid MultiSearch Plugin, Grid MultiSort Plugin, Configuring ViewModel Hierarchy


  4. #4
    Sencha User Lobos's Avatar
    Join Date
    Oct 2007
    Location
    Sao Paulo, Brazil
    Posts
    461
    Vote Rating
    -1
      0  

    Default

    I use a lot of ajax to load ext "modules / classes" into a main layout. This seems to make things load a lot quicker. So say I had a main layout with buttons like add item, contact, etc each of these buttons would load the module required to supply the fuctionality - this could added in tabs or popup windows.

    Not only does everything run faster, it also keeps things organised as each of my modules reside in their own files. Some of the apps I have worked on are so large that it would mean a multiple mb download if everything was in the one file!

    The main thing is to have a good server side framework operating behind this.

    -Lobos

  5. #5
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,664
    Vote Rating
    403
      0  

    Default

    Yes, this is the approach I was also thinking of when application size reaches some limit or when I hit a performance barrier.

    I would basically add point 0 to the above rules that would read 0. Lazy load and would drop point 4, concatenation part.
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid MultiSearch Plugin, Grid MultiSort Plugin, Configuring ViewModel Hierarchy


  6. #6
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    8
      0  

    Default

    Saki

    Seems a little different than your application layout for beginners tutorial. Or would you still use the essence of that layout but reference your preconfigured classes?

    Maybe your comments here have the makings for the follow up tutorial on the subject.

    Are there utilities for concatenating/minimizing/compressing files automatically?

  7. #7
    Sencha User mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
      0  

    Default

    Quote Originally Posted by mjlecomte View Post
    Saki

    Seems a little different than your application layout for beginners tutorial. Or would you still use the essence of that layout but reference your preconfigured classes?

    Maybe your comments here have the makings for the follow up tutorial on the subject.

    Are there utilities for concatenating/minimizing/compressing files automatically?
    tried yuicompressor?

  8. #8
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,664
    Vote Rating
    403
      0  

    Default

    The title of the tutorial says Application Layout for Beginners so I'd expect that one application singleton would do for small application of the beginners. One singleton is just not enough for larger applications that doesn't invalidate in any means it's design or usability for smaller ones.

    Well, I would maybe say that these are general good rules that work for me, however, I do not want to "prescribe" a layout of application for more advanced users. There are many situations that require different approaches. Nevertheless, the rule write good reusable pre-configured classes is really an universal one.

    I use linux, so concat tool is a part of it (cat file1 file2 file3 ... > file-result). There is source code of jsmin (jsmin.c) by Douglas Crockford hanging around on internet - just google for it. Compiling (on linux) is as easy as: cc jsmin.c -o jsmin
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid MultiSearch Plugin, Grid MultiSort Plugin, Configuring ViewModel Hierarchy


  9. #9
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    8
      0  

    Default

    Thanks for your pointers.

    Quote Originally Posted by jsakalos View Post
    The title of the tutorial says Application Layout for Beginners so I'd expect that one application singleton would do for small application of the beginners. One singleton is just not enough for larger applications that doesn't invalidate in any means it's design or usability for smaller ones.
    Isn't this what ry.extjs is pretty much showing in the first post of this thread...that is several singletons or self invoking functions?



    Quote Originally Posted by jsakalos View Post
    Well, I would maybe say that these are general good rules that work for me, however, I do not want to "prescribe" a layout of application for more advanced users.
    Understood, and I probably don't qualify for an advanced user yet, but I am keeping an open mind or an eye out for the path for improvement. So while I've embraced the jist of the beginner application layout, I'm starting to realize it's limitations as my code grows in size and I see the need to make parts of the code reusable, more maintainable, etc.

    I've read up more on different styles of OOP. I guess I'm trying to tap into the experience of someone more experienced as to what they do rather than reinvent the wheel in a sense.

  10. #10
    Sencha User
    Join Date
    Sep 2007
    Location
    Tulsa, Oklahoma
    Posts
    178
    Vote Rating
    1
      0  

    Default

    Quote Originally Posted by Lobos View Post
    I use a lot of ajax to load ext "modules / classes" into a main layout.
    Maybe a noobie question, but when you do this, do you have to eval the "modules / classes"?

    Would you have a small snippet of code or example?

    This is all interesting stuff. Please keep elaborating, I might just learn something!
    Thanks!
    Chuck

Page 1 of 12 12311 ... LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •