Ajax design patterns
Moderator: General Moderators
- inghamn
- Forum Contributor
- Posts: 174
- Joined: Mon Apr 16, 2007 10:33 am
- Location: Bloomington, IN, USA
Re: Ajax design patterns
Just recently something clicked for me with AJAX applications. It was what the term "application" is referring to in the first place. All along I've been doing web applications, which had a ton of screens each at a URL.
A recent conference proceeding made the point for me that, with AJAX stuff, what you're really doing is providing a complete, task-oriented rich "application" at each URL of your website.
So all along, these JavaScript folks have been thinking of applications as just one URL. (Like Yahoo home pages or such.) PHP's job in all this is to deliver the source code for these applications to the browser. And the source code is mix of HTML, CSS, and JavaScript.
PHP also has the job of delivering the data (through web services) needed by these applications.
A recent conference proceeding made the point for me that, with AJAX stuff, what you're really doing is providing a complete, task-oriented rich "application" at each URL of your website.
So all along, these JavaScript folks have been thinking of applications as just one URL. (Like Yahoo home pages or such.) PHP's job in all this is to deliver the source code for these applications to the browser. And the source code is mix of HTML, CSS, and JavaScript.
PHP also has the job of delivering the data (through web services) needed by these applications.
Re: Ajax design patterns
Hm ... yes!arborint wrote:So you have one piece of Javascript code that you load with the main page and that builds the page from JSON data for every page in your site?VladSun wrote:My web-apps are fully AJAX featured. That is, except for the main page HTML View I have no more HTML code. Indeed, I don't have any server side Views - everything is sent to the user as JSON data (if you consider an JSON formatter helper a View ... I have one View). That is, the View part is always client side - no templates, no code duplication (except for the validation, which I think can't be done in other way).
But it's more like a desktop application rather than a collection of web pages ...
A typical web application of mine looks like this:
http://www.extjs.com/deploy/dev/example ... sktop.html
There are 10 types of people in this world, those who understand binary and those who don't
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Ajax design patterns
So following ingham's "every URL is an application" idea ... when do you send a new Javascript? Do you have multiple "main pages"? Or a huge do-everything main Javascript app? Or small focused websites?
(#10850)
Re: Ajax design patterns
One single main page. It loads the core JS libraries and the main Application class. Then it fetches the list of modules available to the current user's role and loads their "meta data". If a module is going to be executed an AJAX call fetches its "real" class and it is run.
There is even a dependency register (in every class declaration), so JS files needed by the class to be loaded are preloaded first.
Also, I won't consider my web applications "small focused" web sites. One of them is a fully featured small ISP management system for back and front office. While one may call it "huge do-everything main Javascript", I think it's modular enough and it works flawlessly.
PS: do you remember this topic : viewtopic.php?f=19&t=93937
There is even a dependency register (in every class declaration), so JS files needed by the class to be loaded are preloaded first.
Also, I won't consider my web applications "small focused" web sites. One of them is a fully featured small ISP management system for back and front office. While one may call it "huge do-everything main Javascript", I think it's modular enough and it works flawlessly.
PS: do you remember this topic : viewtopic.php?f=19&t=93937
There are 10 types of people in this world, those who understand binary and those who don't
Re: Ajax design patterns
So it is 1 class or or not? You said 1 main application class but what is a module meta data? Is all your code abstracted and your modules are simply listings of fields to render in a grid? and things like that?
Re: Ajax design patterns
Well, the Application class depends on several classes:josh wrote:So it is 1 class or or not?
[js]Ext.dependencies ={ application : [ 'ex/app/CurrentUser', 'ex/app/CurrentSettings', 'desktop/AppWatch', 'desktop/StartMenu', 'desktop/TaskBar', 'desktop/Desktop', 'desktop/Module', 'desktop/MRTGModule', 'desktop/ReportModule', 'desktop/Shortcut', 'desktop/Notification', 'desktop/App', 'ex/Sound', 'ex/Image', 'ex/Printer' ],.... [/js]
But there are no classes not related to the framework itself loaded. See what I meant by "meta data" below.
You know that JS classes are prototype based, so you can extend them and their instances at runtime. So ... this is a "meta-class" (see below its "real" class):josh wrote:You said 1 main application class but what is a module meta data?
personnelview-launcher.js
[js](function (){ return ( { translationContext : 'ledger', translationSource : null, dependencies : null, create : function () { Ext.namespace('Ext.Module'); Ext.Module.Ledger = Ext.extend(Ext.app.Module, { moduleId : 'mod-ledger', menuPath : 'StartMenu/' + Ext.Translation.get('menu', 'ledger_menu'), launcher : { iconCls : 'ledger-icon', shortcutIconCls : 'ledger-shortcut', text : Ext.Translation.get('ledger', 'title'), tooltip : Ext.Translation.get('ledger', 'module_description', true) } }); return new Ext.Module.Ledger(); } })})();[/js]
I didn't get this one ... Are you talking about the JS "modules" or for PHP modules?josh wrote:Is all your code abstracted and your modules are simply listings of fields to render in a grid? and things like that?
If you are talking about JS modules - well, they are not so thin:
[js](function (){ return ( { translationContext : 'ledger', translationSource : null, dependencies : Ext.dependencies.singleEditGrid, create : function () { Ext.namespace('Ext.Module'); Ext.override(Ext.Module.Ledger, { init : function () { /* ** ledger JsonStore extended ** */ var ledgerDataStore = new Ext.data.JsonStore( { proxy: new Ext.data.HttpProxy( { url : '/ledger/personnelView', method : 'POST' }), root : 'response', totalProperty : 'totalCount', recordModel : Ext.data.Record.create( [ {name: 'id', type: 'int', defaultValue: 0}, {name: 'operation_id', type: 'int', defaultValue: ''}, {name: 'value', type: 'int', defaultValue: ''}, {name: 'notice', type: 'string', defaultValue: ''} ]), fields : [ {name: 'id', type: 'int' }, {name: 'time', type: 'date', dateFormat : 'Y-m-d H:i:s' }, {name: 'operation_id', type: 'int' }, {name: 'operation_sign',type: 'int'}, {name: 'value', type: 'float' }, {name: 'notice', type: 'string' }, {name: 'username', type: 'string' }, {name: 'fullname', type: 'string' } ], sortInfo : {field: 'time', direction: 'ASC'}, remoteSort : true, autoLoad : true, listeners : { loadexception : { fn : function () { Ext.Msg.error(Ext.Translation.get('common', 'load_data_failure')); } } } }); ledgerDataStore.setDefaultSort('time', 'asc'); this.ledgerOperationDataStore = new Ext.data.JsonStore( { proxy: new Ext.data.HttpProxy( { url : '/ledgeroperation/load', method : 'POST' }), root : 'response', fields : [ {name: 'id', type: 'int'}, {name: 'sign', type: 'int'}, {name: 'visible', type: 'int'}, {name: 'notice', type: 'string'} ], sortInfo : {field: 'notice', direction: 'ASC'}, remoteSort : false, autoLoad : true, listeners : { loadexception : { fn : function () { Ext.Msg.error(Ext.Translation.get('common', 'load_data_failure')); } }, load : { fn : function () { ledgerDataStore.fireEvent('datachanged', ledgerDataStore); } } } }); this.ledgerSignedOperationDataStore = new Ext.data.JsonStore( { proxy: new Ext.data.HttpProxy( { url : '/ledgeroperation/load', method : 'POST' }), root : 'response', fields : [ {name: 'id', type: 'int'}, {name: 'sign', type: 'int'}, {name: 'visible', type: 'int'}, {name: 'notice', type: 'string'} ], sortInfo : {field: 'notice', direction: 'ASC'}, remoteSort : false, autoLoad : true, listeners : { loadexception : { fn : function () { Ext.Msg.error(Ext.Translation.get('common', 'load_data_failure')); } }, load : { scope : this, fn : function () { var sign_income = Ext.Translation.get('ledger', 'sign_income'); var sign_outgo = Ext.Translation.get('ledger', 'sign_outgo'); this.ledgerSignedOperationDataStore.each(function (record) { if (record.get('sign') == 1) record.set('notice', sign_income + ' - ' + record.get('notice')); else record.set('notice', sign_outgo + ' - ' + record.get('notice')); }); this.ledgerSignedOperationDataStore.fireEvent('datachanged', this.ledgerSignedOperationDataStore); } } } }); this.totalsDataStore = new Ext.data.JsonStore( { proxy: new Ext.data.HttpProxy( { url : '/ledger/currentCash', method : 'POST' }), root : 'response', fields : [ {name: 'id', type: 'int'}, {name: 'profit', type: 'int'}, {name: 'income', type: 'int'}, {name: 'outgo', type: 'int'} ], sortInfo : {field: 'id', direction: 'ASC'}, remoteSort : false, autoLoad : true, listeners : { loadexception : { fn : function () { Ext.Msg.error(Ext.Translation.get('common', 'load_data_failure')); } } } }); var totalsColumnModel = new Ext.grid.ColumnModel( { columns: [ { id : 'profit', dataIndex : 'profit', header : Ext.Translation.get('ledger', 'totals_profit_header_text'), renderer : function (val, meta) { if (val.toFixed) { if (val < 0) meta.attr = 'style="color:red;"'; return val.toFixed(2); } else return val; } }, { dataIndex : 'income', header : Ext.Translation.get('ledger', 'totals_income_header_text'), renderer : function (val) { if (val.toFixed) return val.toFixed(2); else return val; } }, { dataIndex : 'outgo', header : Ext.Translation.get('ledger', 'totals_outgo_header_text'), renderer : function (val) { if (val.toFixed) return val.toFixed(2); else return val; } } ] }); totalsColumnModel.defaultSortable = false; var totalsGrid = new Ext.grid.GridPanel( { store : this.totalsDataStore, colModel : totalsColumnModel, loadMask : true, enableColLock : true, enableColumnHide: false, enableHdMenu : false, viewConfig : { forceFit : true }, autoExpandColumn: 'profit' }); /* ** Column model ** */ var expander = new Ext.grid.RowExpander( { tpl : new Ext.Template( '<pre class="expander">{notice}</pre>' ) }); var cm = new Ext.grid.ColumnModel( { columns: [ expander, { dataIndex : 'time', header : Ext.Translation.get('ledger', 'time_header_text'), renderer : function (val) { if (val.format) return val.format('Y-m-d H:i:s'); else return val; } }, { dataIndex : 'username', header : Ext.Translation.get('ledger', 'username_header_text'), renderer : function (val, meta, rec) { return rec.get('fullname') + ' (' + val + ')'; } }, { dataIndex : 'operation_sign', header : Ext.Translation.get('ledger', 'operation_sign_header_text'), renderer : function (val, meta) { if (val > 0) { meta.attr = 'style="color:green"'; return Ext.Translation.get('ledger', 'sign_income'); } else { meta.attr = 'style="color:red"'; return Ext.Translation.get('ledger', 'sign_outgo'); } } }, { dataIndex : 'operation_id', header : Ext.Translation.get('ledger', 'operation_header_text'), id : 'operation_id', store : this.ledgerOperationDataStore, displayField: 'notice', valueField : 'id' }, { dataIndex : 'value', header : Ext.Translation.get('ledger', 'value_header_text'), renderer : function (val) { if (val.toFixed) return val.toFixed(2); else return val; } } ] }); cm.defaultSortable = true; /* ** Grid ** */ var grid = new Ext.ex.grid.SingleEditGridPanel( { scope : this, baseUrl : 'ledger', toolButtons : + Ext.ex.grid.SingleEditGridPanel.constant.hasAddButton, store : ledgerDataStore, colModel : cm, enableColLock : false, plugins : [ new Ext.ex.grid.ComboField(), expander ], autoExpandColumn: 'notice', getEditWindowConfig : function () { return ( { title : Ext.Translation.get('ledger', 'ledger_properties_window_title') }); }, getEditFormConfig : function (record, self) { return ( { items : [ { name : 'operation_id', xtype : 'combo', fieldLabel : Ext.Translation.get('ledger', 'operation_header_text'), mode : 'local', autoWidth : true, store : self.ledgerSignedOperationDataStore, editable : false, allowBlank : false, triggerAction: 'all', displayField: 'notice', valueField : 'id', listClass : 'x-combo-list-small' }, { name : 'notice', xtype : 'textarea', maxLength : 500, fieldLabel : Ext.Translation.get('ledger', 'notice_header_text'), allowBlank : false }, { name : 'value', vtype : 'money', minValue : 0.01, xtype : 'numberfield', fieldLabel : Ext.Translation.get('ledger', 'value_header_text'), allowBlank : false } ] }); } }); this.winConfig = { items : { xtype : 'panel', layout : 'border', items : [ { xtype : 'panel', layout : 'fit', items : grid, region : 'center' }, { xtype : 'panel', layout : 'fit', items : totalsGrid, height : 70, region : 'south' } ] }, title : Ext.Translation.get('ledger', 'title') }; } }); } })})(); [/js]
While most of the back office modules are grid based, front office modules are much more complex:
[js]... this.tabPanel = new Ext.TabPanel( { resizeTabs : true, minTabWidth : 115, tabWidth : 135, autoWidth : true, enableTabScroll : true, activeTab : 0, defaults : { autoScroll : true, labelWidth : 120 }, bbar : [ this.resetButton ], items : [ this.personalDataForm, this.internetDataForm ] }); this.searchPanel = new Ext.Panel( { region : 'west', width : 320, layout : 'fit', items : this.tabPanel }); this.resultsPanel = new Ext.Panel( { region : 'center', width : 400, items : this.userGrid }); this.container = new Ext.Panel( { layout : 'border', frame : true, defaults : { layout : 'fit' }, items : [ this.searchPanel, this.resultsPanel ] }); this.winConfig = { items : this.container, title : Ext.Translation.get('payment', 'title') }; }[/js]
It's just the visual layout ...
Last edited by VladSun on Fri Dec 17, 2010 4:19 am, edited 1 time in total.
There are 10 types of people in this world, those who understand binary and those who don't
-
alex.barylski
- DevNet Evangelist
- Posts: 6267
- Joined: Tue Dec 21, 2004 5:00 pm
- Location: Winnipeg
Re: Ajax design patterns
I`m right in the process of looking for an interesting web desktop interface for my own framework...that was so slick...I started cryingHm ... yes!
But it's more like a desktop application rather than a collection of web pages ...
A typical web application of mine looks like this:
http://www.extjs.com/deploy/dev/example ... sktop.html
Thanks man
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Ajax design patterns
Vlad, you showed a lot of code that seems pretty Ext-centric. Is this stuff that could be done with any Javascript library? Or does Ext provide the functionality that makes what you are doing easy?
(#10850)
Re: Ajax design patterns
Yes, most of it is ExtJS specific ...
I do love ExtJS
and I always try to show its power to other developers - I think you've noticed it 
http://www.extjs.com/deploy/dev/docs/
I do love ExtJS
http://www.extjs.com/deploy/dev/docs/
There are 10 types of people in this world, those who understand binary and those who don't
Re: Ajax design patterns
In my opinion, developing all the views in Javascript is very unportable. Often, I need to create low-FI versions of my web apps, for mobile consumption or other edge cases, in which case I'd need it to run similarly but without the Javascript. I use Javascript to create an enhanced interface for those with modern browsers, but keep the option to reuse view elements in other usecases.
Re: Ajax design patterns
Sorry, missed that one.PCSpectra wrote:So what happens when someone visits your site on a mobile device like a blackberry, which might not have JS enabled by default? If templates rendered via client side (using XSLT, or whatever) chances are a mobile will not render anything but simple HTML.My web-apps are fully AJAX featured. That is, except for the main page HTML View I have no more HTML code. Indeed, I don't have any server side Views - everything is sent to the user as JSON data (if you consider an JSON formatter helper a View ... I have one View ). That is, the View part is always client side - no templates, no code duplication (except for the validation, which I think can't be done in other way).
No to mention SEF/SEO. Unless your pages are purely XML data structures which are rendered into HTML (but I recall JSON being the term) how does that affect SE's???
I develop desktop web applications which are run in an Intranet environment, strictly specified browser (usually Prism), etc.
So it's easy for me - no SEO, no cross-browser issues
Also, I've really never cared about mobile devices - people using such devices 1) are too rare in our country and 2) are simply not in our target group. And SEO may be achieved in several ways -e.g. by using the Google XML sitemap tool. Also, I do think search engines should follow the Internet evolution, not the opposite - I mean SE should use RIA-enabled spiders
There are 10 types of people in this world, those who understand binary and those who don't
Re: Ajax design patterns
Back to the topic
Any comments on this one?VladSun wrote:Just today, I've read a short article about MVC and AJAX - http://wiki.apidesign.org/wiki/MVC
So, we have MVP hereTo MVP Again
Obviously, people tend to repeat the same thing again and again, just with new technologies. Thus with the rise of Ajax, where the GUI is represented inside a browser we are again closer to MVP as the user deals with the view elements directly.
There are 10 types of people in this world, those who understand binary and those who don't
Re: Ajax design patterns
Haven't followed the details exactly, but I do think that if you throw out URLs completely by using a full ajax approach for web apps, you loose a lot. Easy to remember or predictable urls, back-button functionality, good inexibility by search engines, etc
Re: Ajax design patterns
I would say Vlad's case is not applicable to most of us since he develops desktop applications which run in a browser. They work over an intranet and specific browser only. Most of us develop web applications / websites that are served to the mass population and have to worry about cross-browser support, mobile support, various resolutions etc.
-
alex.barylski
- DevNet Evangelist
- Posts: 6267
- Joined: Tue Dec 21, 2004 5:00 pm
- Location: Winnipeg
Re: Ajax design patterns
I wanna figure out a way so my users can switch between an AJAX interface like those supplied by that library and one which is statically displayed, such as HTML.
Have you looked at some of those screenies? Oh man...thats awesome
Have you looked at some of those screenies? Oh man...thats awesome