Ext.require([ 'Ext.data.*', 'Ext.panel.Panel', 'Ext.layout.container.Card', 'Ext.tip.QuickTipManager' ]); Ext.define('Customer', { extend: 'Ext.data.Model', fields: [{ name: 'id', type: 'int' }, 'name', 'phone'], associations: [{ model: 'Order', type: 'hasMany', autoLoad: true }], proxy: { type: 'ajax', url: 'customer.php' } }); Ext.define('Order', { extend: 'Ext.data.Model', fields: [{ name: 'id', type: 'int' },{ name: 'customer_id', type: 'int' },{ name: 'date', type: 'date', dateFormat: 'Y-m-d' }], belongsTo: 'Customer', associations: [{ model: 'OrderItem', type: 'hasMany', autoLoad: true }], proxy: { type: 'ajax', url: 'order.php' } }); Ext.define('OrderItem', { extend: 'Ext.data.Model', fields: [{ name: 'id', type: 'int' }, { name: 'order_id', type: 'int' },'product', { name: 'quantity', type: 'int' }, { name: 'price', type: 'float' }], belongsTo: 'Order', proxy: { type: 'ajax', url: 'orderitem.php' } }); Ext.define('CustomerGrid', { extend: 'Ext.grid.Panel', alias: 'widget.customergrid', title: 'Customers', initComponent: function(){ Ext.apply(this, { store: { autoLoad: true, model: 'Customer', listeners: { load: function() { Logger.log('Customer store loaded', false); } } }, columns: [{ text: 'Id', dataIndex: 'id' },{ text: 'Name', dataIndex: 'name', flex: 1 }, { text: 'Phone', dataIndex: 'phone' }], dockedItems: [{ xtype: 'toolbar', items: { itemId: 'load', text: 'Load Orders', scope: this, handler: this.loadOrders, disabled: true } }] }); this.callParent(); this.getSelectionModel().on('selectionchange', this.onSelectChange, this); }, onSelectChange: function(selModel, selections) { this.active = selections[0]; this.down('#load').setDisabled(!this.active); }, loadOrders: function(){ var rec = this.active, name = rec.get('name'), owner = this.ownerCt, orders; orders = rec.orders(); if (orders.isLoading()) { Logger.log('Begin loading orders: ' + rec.getId(), true); } orders.on('load', function(){ Logger.log('Order store loaded - ' + rec.getId(), false); }); owner.add({ title: 'Orders - ' + rec.getId(), customer: rec, xtype: 'ordergrid', store: orders }); owner.getLayout().next(); } }); Ext.define('OrderGrid', { extend: 'Ext.grid.Panel', alias: 'widget.ordergrid', initComponent: function(){ Ext.apply(this, { columns: [{ text: 'Id', dataIndex: 'id' },{ flex: 1, text: 'Date', dataIndex: 'date', renderer: Ext.util.Format.dateRenderer('Y-m-d') }], dockedItems: [{ xtype: 'toolbar', items: [{ text: 'Back', scope: this, handler: this.onBackClick },{ itemId: 'load', text: 'Load Order Items', scope: this, handler: this.loadItems, disabled: true }] }] }); this.callParent(); this.getSelectionModel().on('selectionchange', this.onSelectChange, this); }, onBackClick: function(){ this.ownerCt.getLayout().prev(); this.destroy(); }, onSelectChange: function(selModel, selections) { this.active = selections[0]; this.down('#load').setDisabled(!this.active); }, loadItems: function(){ var customerName = this.customer.get('name'), rec = this.active, date = Ext.Date.format(rec.get('date'), 'Y-m-d'), owner = this.ownerCt, orderitems; orderitems = rec.orderitems(); if (orderitems.isLoading()) { Logger.log('Begin loading order items - ' + rec.getId(), true); } orderitems.on('load', function(){ Logger.log('Order items loaded - ' + rec.getId(), false); }); owner.add({ title: 'Order Items - ' + rec.getId(), xtype: 'orderitemgrid', store: orderitems }); owner.getLayout().next(); } }); Ext.define('OrderItemGrid', { extend: 'Ext.grid.Panel', alias: 'widget.orderitemgrid', initComponent: function(){ Ext.apply(this, { columns: [{ text: 'Id', dataIndex: 'id' },{ flex: 1, text: 'Product', dataIndex: 'product' }, { text: 'Quantity', dataIndex: 'quantity' }, { text: 'Price', dataIndex: 'price', renderer: Ext.util.Format.usMoney }], dockedItems: [{ xtype: 'toolbar', items: [{ text: 'Back', scope: this, handler: this.onBackClick }, { itemId: 'load', text: 'Parent association loader', tooltip: 'Demonstrate loading parent relationships - A new record will be created so we ignore any previous associations setup', scope: this, handler: this.onLoadClick, disabled: true }] }] }); this.callParent(); this.getSelectionModel().on('selectionchange', this.onSelectChange, this); }, onSelectChange: function(selModel, selections) { this.active = selections[0]; this.down('#load').setDisabled(!this.active); }, onBackClick: function(){ this.ownerCt.getLayout().prev(); this.destroy(); }, onLoadClick: function(){ var rec = this.active, id = rec.getId(); new ItemLoader({ width: 400, height: 400, modal: true, title: this.title.replace('Order Items', 'Order Item ' + id), orderItemData: rec.data, orderItemId: id }).show(); } }); Ext.define('ItemLoader', { extend: 'Ext.window.Window', initComponent: function(){ Ext.apply(this, { border: false, autoScroll: true, dockedItems: [{ xtype: 'toolbar', items: [{ text: 'Print order detail', scope: this, handler: this.onOrderClick }, { itemId: 'company', text: 'Print company detail', disabled: true, scope: this, handler: this.onCompanyClick }] }], bodyPadding: 5, tpl: '