.. / Шаг 1. Зарождение собственного компонента в ExtJS

  1. ExtJS-large-application

Для начала нужно разобраться с классами на примере простой таблицы. Потом на этом месте вырастет большой компонент, который включает в себя табличку с фильтрами для поиска и сортировки, меню групповых команд, редактор и просмотрщик. Но это будет потом. Сейчас оттолкнусь от того что было раньше когда я сделал самую простую табличку с Ajax-загрузкой.

Общий код остается практически таким же таким каким он и был. В архиве step1 это файл /grid.htm

Ext.onReady(function(){

    var store = Ext.create('Ext.data.JsonStore', {     // создаем хранилища для удаленного источника данных
      fields: ['id', 'name'],   // поля записей
      autoLoad: true,
      pageSize:25,
      remoteFilter:true,
      proxy: {  type: 'ajax',
                url:'/data/sql.php?type=first',
                reader: {type: 'json',root: 'data'}},
      });
    var grid = Ext.create('Ext.grid.Panel', {   // создаем сетку
        renderTo:'q',
        store: store,               // определили хранилище
        columns:[
                    {text: 'id', dataIndex: 'id'},
                    {text: 'name',      dataIndex: 'name'}
                ],
        bbar: new Ext.PagingToolbar({   // bbar - нижний тулбар с листалкой
            store: store,               // указано хранилище
            displayInfo: true,          // вывести инфо обо общем числе записей
            displayMsg: 'Показано  {0} - {1} из {2}' // формат инфо
        })
    });


});

Табличек будет много и у каждой будет свой источник данных, следоваткльно у каждой таблички должно быть свое собственное хранилище. Поэтому перейду к созданию класса сетки, который сам будет создавать хранилище и настраивать его по необходимости. Поскольку этот класс общий и является базой для других классов для него я выделю место в пространстве имен App.Common и соответственно держать буду в директории app.Common

Здесь будет несколько сложнее и мне понадобится то, что в заметках не возникало - конструктор объекта initComponent. Код находится в grid3.htm

Ext.define(«App.Common.CommonGrid»,{
      extend: 'Ext.grid.Panel',
      alias: «widget.commongrid»,
      frame: true,
      columns:[
                    {text: 'id', dataIndex: 'id'},
                    {text: 'name',      dataIndex: 'name'}
                ],

      /* инициализация  *********************************************************/
      initComponent: function() {
                    this.columns=this.conf.columns;
                    this.store= Ext.create('Ext.data.Store',{
                        autoLoad: true,
                        fields:['id','name'],
                        pageSize:25,
                        remoteFilter:true,
                        proxy: {
                        url:this.conf.url,
                                type: 'ajax',
                        reader: {type: 'json',root: 'data'}
                        }
                      });
                    this.bbar = new Ext.PagingToolbar({
                            store: this.store,
                                displayInfo: true,
                            pageSize:25,
                                displayMsg: 'Показано  {0} - {1} из {2}'
                         }); App.Common.CommonGrid.superclass.initComponent.apply(this, arguments);
                }


    });
    });


    var grid = Ext.create('App.Common.CommonGrid', {renderTo:'q'});

Когда вызывается конструктор initComponent к объекту добавлять какие-то другие компоненты, и настройки, которые передали через параметры при создании экземпляра объекта. Чего не хватает в полученном классе - как минимум, адреса источника данных и отображаемых полей таблички, которые для каждого экземпляра класса моего мегаприложения будут разными - таблички с авторами, текстами, ссылками, сообщениями в форуме и т.д. И следующим шагом будет создание класса таблички, которую можно гибко настроить через файл конфигурации. Все что будет сделано находится в файле grid4.htm И кроме того на этом этапе имеет смысл объединения данных. В этом примере поля хранилища совпадают с колонками таблицы.

Теперь полностью перепишу initComponent для CommonGrid, и в конфиге создам свой собственный блок параметров - объект conf через который можно будет задавать параметры для CommonGrid, не перемешивая их с теми, которые зашиты в родительский класс Ext.grid.Panel. Позже я расширять CommonGrid, создавать на его основе новые классы, но этот самый conf будет использоваться практически всюду.

Код примера в grid4.htm

Ext.define(«App.Common.CommonGrid»,{. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. … 
      conf: {
        grid:{columns:[
                    {text: 'id', dataIndex: 'id'},
                    {text: 'name',      dataIndex: 'name'}
                ]}
      },
      initComponent: function() {
                    this.columns=this.conf.grid.columns;
                    var i,fields=[];
                    for (i in this.columns) {fields.push(this.columns[i].dataIndex);} // fields для store выбирается из колонок
                    this.store= Ext.create('Ext.data.Store',{
                        autoLoad: true,
                        fields:fields, 
                        pageSize:25,
                        remoteFilter:true,
                        proxy: {
                        url:this.conf.url, // адрес источника из собств конф. 
                                type: 'ajax',
                            reader: {
                                type: 'json',
                                root: 'data'
                            }
                        }
                      });
          .. .. .. .. .. .. .. .. .. .. .. .. .. … 
                }
    })

Что я сделал? Во-первых, расширил структуру conf, потому что дальше кроме самой таблички в этом компоненте появятся какие-нибудь дополнительные кастомные элементы. Через conf.grid.columns перечень колонок в таблице. Этот же перечень используется и в полях хранилища store. Таким образом не нужно определять дважды одно и то же как было раньше. В 99% случаев это решает все необходимые задачи. Когда возникнет необходимость ввести какие-то составные колонки, или невизуальные поля в хранилище, тогда эти данные можно расширить и переопределить и уж точно часть задачи по формированию какого-то специфического вида колонок можно перенести в серверную часть.

Ну и теперь самое логичное - попытаюсь создать две таблицы с разными данными используя свой собственный класс App.CommonGrid. Листинг в grid5.htm. Здесь я уже не возвращаюсь к компоненту, а просто использую его для создания двух разных таблиц с двумя разными источниками данных

  var grid1 = Ext.create('App.Common.CommonGrid', {   // создаем сетку
        renderTo:'q1',
      conf: {
        url:'/data/sql.php?type=first',
        grid:{columns:[
                    {text: 'id', dataIndex: 'id'},
                    {text: 'Название',      dataIndex: 'name'}
                ]}
      },
    });

    var grid2 = Ext.create('App.CommonGrid', {   // создаем сетку
        renderTo:'q2',
      conf: {
        url:'/data/sql.php?type=second',
        grid:{columns:[
                    {text: 'id', dataIndex: 'id'},
                    {text: 'Имя',      dataIndex: 'name'}
                ]}
      },
    });

И наконец самый последний шаг. То что получилось это всего-навсего заготовка. Реально в моем приложении будет отображаться одновременно несколько табличек типа first и типа second. И эти таблички будут отличаться значительно больше чем в примере - у них могут быть свои собственные поисковые формы, фильтры, меню и т.п. Поэтому рационально было бы этот шаг закончить созданием классов First и Second, которые будут наследоваться от CommonGrid. Далее по п.п.

1

Выкладываю класс CommonGrid в отдельный файл /app/Common/CommonGrid.js

2

В /app/ создаю два новых класса First и Second (в файлах First.js и Second.js)

**********first.js**************** Ext.define(«App.First»,{
      extend: 'App.Common.CommonGrid',
      alias: «widget.first»,
      conf:  {
        url:'/data/sql.php?type=first',
        columns:[
                    {text: 'id', dataIndex: 'id',width:60},
                    {text: 'Название',      dataIndex: 'name',flex:true}
                ]
      },

    });

**********second.js**************** Ext.define(«App.Second»,{
      extend: 'App.Common.CommonGrid',
      alias: «widget.second»,
      conf:  {
        url:'/data/sql.php?type=second',

        columns:[
                    {text: 'id', dataIndex: 'id',width:100},
                    {text: 'Имя',      dataIndex: 'name',width:100},
                    {text: 'Фамилия',  dataIndex: 'f', flex:true}
                ]
      },

    });

Код который создает два разных экземпляра этих классов в файле grid6.htm

    var grid1 = Ext.create('App.First', {   // создаем сетку
        renderTo:'q1'
    });
    var grid2 = Ext.create('App.Second', {   // создаем сетку
        renderTo:'q2'
    });

Все что получилось аккуратно упаковываю и кладу в архив my_big_application_ExtJS4.zip в директорию step1

  1. 2012-03-15
  2. ExtJS-large-application
  1. www.sencha.com/forum/archive/index.php/t-124740.html?s=656b4337e47b9419755bf0a6bc7409e9 - ExtJS 4. Constructor or initComponent?
  2. erum.ru/82.htm - Шаг 2. Каркас большого приложения
  3. stackoverflow.com/questions/3171946/extjs-extend-class-via-constructor-or-initcomponent - Extjs: extend class via constructor or initComponent?
  4. www.sencha.com/learn/legacy/Tutorial:Extending_Ext_for_Newbies - Tutorial:Extending Ext for Newbies
  5. erum.ru/54.htm - 8.2 ExtJS: GridPanel загрузка данных из Ajax
Go Index Test