Ext.require([ 'Ext.grid.*', 'Ext.data.*', 'Ext.panel.*', 'Ext.layout.container.Border' ]); Ext.Loader.onReady(function() { Ext.define('Book',{ extend: 'Ext.data.Model', proxy: { type: 'ajax', reader: 'xml' }, fields: [ // set up the fields mapping into the xml doc // The first needs mapping, the others are very basic {name: 'Author', mapping: '@author.name'}, 'Title', 'Manufacturer', 'ProductGroup', 'DetailPageURL' ] }); /** * App.BookStore * @extends Ext.data.Store * @cfg {String} url This will be a url of a location to load the BookStore * This is a specialized Store which maintains books. * It already knows about Amazon's XML definition and will expose the following * Record defintion: * - Author * - Manufacturer * - ProductGroup * - DetailPageURL */ Ext.define('App.BookStore', { extend: 'Ext.data.Store', constructor: function(config) { config = config || {}; config.model = 'Book'; config.proxy = { type: 'ajax', url: 'sheldon.xml', reader: Ext.create('Ext.data.reader.Xml', { // records will have an "Item" tag record: 'Item', id: 'ASIN', totalRecords: '@total' }) }; // call the superclass's constructor this.callParent([config]); } }); /** * App.BookGrid * @extends Ext.grid.Panel * This is a custom grid which will display book information. It is tied to * a specific record definition by the dataIndex properties. * * It follows a very custom pattern used only when extending Ext.Components * in which you can omit the constructor. * * It also registers the class with the Component Manager with an xtype of * bookgrid. This allows the application to take care of the lazy-instatiation * facilities provided in Ext's Component Model. */ Ext.define('App.BookGrid', { extend: 'Ext.grid.Panel', // This will associate an string representation of a class // (called an xtype) with the Component Manager // It allows you to support lazy instantiation of your components alias: 'widget.bookgrid', // override initComponent : function() { // Pass in a column model definition // Note that the DetailPageURL was defined in the record definition but is not used // here. That is okay. this.columns = [ {text: "Author", width: 120, dataIndex: 'Author', sortable: true}, {text: "Title", flex: 1, dataIndex: 'Title', sortable: true}, {text: "Manufacturer", width: 125, dataIndex: 'Manufacturer', sortable: true}, {text: "Product Group", width: 125, dataIndex: 'ProductGroup', sortable: true} ]; // Note the use of a storeId, this will register thisStore // with the StoreManager and allow us to retrieve it very easily. this.store = new App.BookStore({ storeId: 'gridBookStore', url: 'sheldon.xml' }); // finally call the superclasses implementation this.callParent(); } }); /** * App.BookDetail * @extends Ext.Panel * This is a specialized Panel which is used to show information about * a book. * * This demonstrates adding 2 custom properties (tplMarkup and * startingMarkup) to the class. It also overrides the initComponent * method and adds a new method called updateDetail. * * The class will be registered with an xtype of 'bookdetail' */ Ext.define('App.BookDetail', { extend: 'Ext.Panel', // register the App.BookDetail class with an xtype of bookdetail alias: 'widget.bookdetail', // add tplMarkup as a new property tpl: [ 'Title: {Title}
', 'Author: {Author}
', 'Manufacturer: {Manufacturer}
', 'Product Group: {ProductGroup}
' ], // startingMarup as a new property startingMarkup: 'Please select a book to see additional details', bodyPadding: 7, // override initComponent to create and compile the template // apply styles to the body of the panel and initialize // html to startingMarkup initComponent: function() { this.html = this.startingMarkup; // call the superclass's initComponent implementation this.callParent(); } }); /** * App.BookMasterDetail * @extends Ext.Panel * * This is a specialized panel which is composed of both a bookgrid * and a bookdetail panel. It provides the glue between the two * components to allow them to communicate. You could consider this * the actual application. * */ Ext.define('App.BookMasterDetail', { extend: 'Ext.Panel', alias: 'widget.bookmasterdetail', frame: true, title: 'Book List', width: 580, height: 400, layout: 'border', // override initComponent initComponent: function() { this.items = [{ xtype: 'bookgrid', itemId: 'gridPanel', region: 'north', height: 210, split: true },{ xtype: 'bookdetail', itemId: 'detailPanel', region: 'center' }]; // call the superclass's initComponent implementation this.callParent(); }, // override initEvents initEvents: function() { // call the superclass's initEvents implementation this.callParent(); // now add application specific events // notice we use the selectionmodel's rowselect event rather // than a click event from the grid to provide key navigation // as well as mouse navigation var bookGridSm = this.getComponent('gridPanel').getSelectionModel(); bookGridSm.on('selectionchange', this.onRowSelect, this); }, // add a method called onRowSelect // This matches the method signature as defined by the 'rowselect' // event defined in Ext.selection.RowModel onRowSelect: function(sm, rs) { // getComponent will retrieve itemId's or id's. Note that itemId's // are scoped locally to this instance of a component to avoid // conflicts with the ComponentManager if (rs.length) { var detailPanel = this.getComponent('detailPanel'); detailPanel.update(rs[0].getData()); } } }); // do NOT wait until the DOM is ready to run this }, false); // Finally now that we've defined all of our classes we can instantiate // an instance of the app and renderTo an existing div called 'binding-example' // Note now that classes have encapsulated this behavior we can easily create // an instance of this app to be used in many different contexts, you could // easily place this application in an Ext.Window for example Ext.onReady(function() { // create an instance of the app var bookApp = new App.BookMasterDetail({ renderTo: 'binding-example' }); // We can retrieve a reference to the data store // via the StoreManager by its storeId Ext.data.StoreManager.get('gridBookStore').load(); });