Ext


Go Back   Ext JS Forums > Ext General Forums > Ext: Open Discussion

Reply
 
Thread Tools
  #1  
Old 02-18-2008, 11:41 AM
ry.extjs ry.extjs is offline
Ext User
 
Join Date: Jan 2008
Posts: 103
ry.extjs is on a distinguished road
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

// 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.
Reply With Quote
  #2  
Old 02-18-2008, 12:47 PM
mjlecomte mjlecomte is offline
Ext JS - Quality Assurance Team
 
Join Date: Jul 2007
Location: Florida
Posts: 10,008
mjlecomte is on a distinguished road
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?
Reply With Quote
  #3  
Old 02-18-2008, 02:08 PM
jsakalos's Avatar
jsakalos jsakalos is online now
Ext JS - Support Team
 
Join Date: Apr 2007
Location: Slovakia
Posts: 14,641
jsakalos will become famous soon enough
Send a message via Skype™ to jsakalos
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:

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

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.
Reply With Quote
  #4  
Old 02-18-2008, 04:08 PM
Lobos's Avatar
Lobos Lobos is offline
Ext User
 
Join Date: Oct 2007
Location: Sao Paulo, Brazil
Posts: 433
Lobos is on a distinguished road
Send a message via MSN to Lobos
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
Reply With Quote
  #5  
Old 02-18-2008, 04:28 PM
jsakalos's Avatar
jsakalos jsakalos is online now
Ext JS - Support Team
 
Join Date: Apr 2007
Location: Slovakia
Posts: 14,641
jsakalos will become famous soon enough
Send a message via Skype™ to jsakalos
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.
Reply With Quote
  #6  
Old 02-18-2008, 08:06 PM
mjlecomte mjlecomte is offline
Ext JS - Quality Assurance Team
 
Join Date: Jul 2007
Location: Florida
Posts: 10,008
mjlecomte is on a distinguished road
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?
Reply With Quote
  #7  
Old 02-18-2008, 08:26 PM
mystix's Avatar
mystix mystix is offline
Ext JS - Community Support Team
 
Join Date: Mar 2007
Location: Singapore
Posts: 5,831
mystix is on a distinguished road
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?
__________________


3.x - ( Docs | Examples | SVN Log ) / 2.x - ( Docs | Examples )
HOWTO - ( Report Bugs | Post Proper Code ) / Learn / Saki's Examples
Forum Search (FF/IE plugin) / API Search (FF/IE plugin)
Reply With Quote
  #8  
Old 02-18-2008, 08:32 PM
jsakalos's Avatar
jsakalos jsakalos is online now
Ext JS - Support Team
 
Join Date: Apr 2007
Location: Slovakia
Posts: 14,641
jsakalos will become famous soon enough
Send a message via Skype™ to jsakalos
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
Reply With Quote
  #9  
Old 02-18-2008, 09:07 PM
mjlecomte mjlecomte is offline
Ext JS - Quality Assurance Team
 
Join Date: Jul 2007
Location: Florida
Posts: 10,008
mjlecomte is on a distinguished road
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.
Reply With Quote
  #10  
Old 02-18-2008, 09:20 PM
ckr ckr is offline
Ext User
 
Join Date: Sep 2007
Location: Tulsa, Oklahoma
Posts: 163
ckr is on a distinguished road
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
Reply With Quote
Reply

Thread Tools

Posting Rules

Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

All times are GMT -5. The time now is 01:50 PM.

© 2006-2009 Ext, LLC
Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.