.. / Шаг 6. Дополняю сетку CommonGrid поиском и возможностью добавить новую запись

  1. ExtJS-large-application

Часть 1 Форма поиска

Очевидно что в любом подобном приложении должен быть какой-то минимальный функционал для выборки записей из таблицы - по ключевым словам и каким-то другим критериям. Например в CMS это может быть поиск/фильтрация статей по авторам, рубрикам, тегам и т.п. До кучи нужна возможность добавления групповых операций типа удаления, публикации или переноса статей в другой раздел. Групповые операции я рассматривать не буду. Не имеет смысла, а вот поиск обязательно сделаю, потому что он выявит очередную болезнь роста моего "большого" приложения.

Очевидно что поиск/фильтрация должны быть разными для разных типов объектов. Хотя в большинстве случаев достаточно поиска по ключевому слову, а иногда и этого не нужно, но в отдельных случаях придется городить формы поиска из большого числа компонент. Чтобы не загромождать CommonGrid я создаю отдельный компонент, в котором будет организована подгрузка кастомных классов поиска, выполнение фильтрации, а позже и все что связано с групповыми операциями.

В самом CommonGrid я ограничусь только одной строкой вызова в его конструкторе:

initComponent: function() {
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
                    this.tbar = new App.Common.CommonGridTBar({grid:this});
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }

При создании тулбара я передаю туда ссылку на создаваемый экземпляр CommonGrid. Из нее тулбар сам подтянет необходимые данные.

А вот код класса CommonGridTBar - тулбара для CommonGrid:

Ext.define("App.Common.CommonGridTBar",
  {
         extend: 'Ext.toolbar.Toolbar',
         height:32, // задаю высоту иначе начинаются прыжки
         items:[],  
         initComponent: function() {
              App.Common.CommonGridTBar.superclass.initComponent.apply(this, arguments);
              // определяю имя кастомного класса для формы поиска
              var   that = this,
                    grid = this.grid,
                    appForm = grid.family+'FormSearch';

              Ext.require(         // загружаю класс кастомной формы поиска;
                      appForm,function(){
                           var form = Ext.create(appForm,{grid:grid});
                           that.add(['->',form]);
                        }
                   );
         }
   }

)

Мне кажется из комментариев должно быть все ясно. Я создаю меню, которое на сеогдняшний день должно охватывать 99% всех моих задач. И так же как и раньше я определяю класс кастомного компонента, отвечающего за форму поиска подгружаю его, инициализирую форму поиска и вставляю его в тулбар. Код класса поисковой формы для First приведу ниже

Ext.define("App.FirstFormSearch",
  {
         extend: 'Ext.form.Panel',
         bodyStyle: 'background:none; border:none;',
         layout: 'hbox',
         width:400,
         items:[
                   {xtype : 'textfield',name      : 'query',emptyText : 'Введите ключевое слово',flex:1},
                   {xtype:"button",itemId:'find',cls: 'x-form-search-trigger',margin: '0 1 0 1'},
                   {xtype:"button",itemId:'clear',cls: 'x-form-clear-trigger'}
         ],
         initComponent: function() {
              App.FirstFormSearch.superclass.initComponent.apply(this, arguments);
              // определяю реакцию на нажатие кнопок поиска
              this.getComponent('find').on('click',this.formFind,this);
              this.getComponent('clear').on('click',this.formClear,this);

          },
          formFind:function(){ // поиск
              var filters=[];
              // считываю данные формы
              var data=this.form.getValues();
              // преобразую данные в идиотский вид, требуемый ExtJS
              for (i in data) filters.push({property:i,value:data[i]});
              // перегружаю данные хранилища с учетом фильтров через глобальный обозреватель
              this.grid.store.load({filters:filters,itemId:this.grid.itemId,start:0,page:0});
          },
          formClear:function(){  // сброс поиска
              this.reset();
              this.formFind();
          }
    }
)

Поскольку код для большинства случаев будет отличаться незначительно - только набором контролов, на базе этого класса я создам общий класс для формы поиска в тулбаре - App.Common.CommonFormSearch. Его код отличается от приведенного выше только тем, что items задающий список необходимых полей формы будет браться из конфигурации кастомного класса, вот так:

Ext.define("App.ThirdFormSearch",{extend: 'App.Common.CommonFormSearch',
conf:{
  items:[{
                  name: 'genre',
                  xtype:'combo',
                  emptyText : 'Выберите рубрику',
                  store:  {
                  fields: ['v', 'w'],
                  data : [
                            {w:'анимация',v:'анимация'},
                            {w:'биография',v:'биография'},
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
                          ]},
                displayField: 'w', // это текстовое значение 
               valueField: 'v'   // а это значение поля 

  }, {xtype : 'textfield',name : 'query',emptyText : 'Введите ключевое слово',flex:1} ] } });

при этом если дополнительная конфигурация отсутствует будет выведено только поле поиска по ключевому слову.

Часть 2. Меню в тулбаре

Для создания меню в тулбаре чуть переделаю код CommonGridTBar:

Ext.define("App.Common.CommonGridTBar",
  {
         extend: 'Ext.toolbar.Toolbar',
         height:32,
         items:[ // создаю меню, пока пустое
                {itemId:'create',text:'Создать',iconCls: 'edit'},
                {text:'Вид', menu:{}},
                {text:'Группа', menu: {}}],
         initComponent: function() {
              App.Common.CommonGridTBar.superclass.initComponent.apply(this, arguments);
              // определяю имя кастомного класса для формы поиска
              var   that = this,
                    grid = this.grid,
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
// здесь отработка нажатия кнопки "создать" в меню
              this.getComponent('create').on('click',function(){
                  var data =  {
                        rec:{id:0},
                        url:grid.store.proxy.url,
                        family:grid.family,
                        itemId:grid.itemId
                    }
                  app.Event.fire('edit', data);
              });



         }
   }

)

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

Для того чтобы создание новой записи работало, мне пришлось несущественно переделать и код редактора. Но я его приводить не буду. Отмечу только что при создании новой записи редактор через глобальный обозреватель посылает табличке сообщение о том что необходимо перезагрузить табличку и отобрасить первую страницу. В этом случае если на сервере записи отсортированы по убыванию ID, новая запись будет в ней отображаться на первом месте. Что будет если сортировка сделан по другому - х.з. Я не придумал как должно быть, но новая запись должна как-то отображаться.

Часть 3. Резюме

На этом все. Все что получилось аккуратно упаковываю и кладу в архив my_big_application_ExtJS4.zip в директорию step6. Дальше наращивание функционала будет проходить по тем же самым рельсам и в сторону дальнейшей кастомизации приложения. Поэтому выкладывание в блог уже не имеет никакого смысла. Но поскольку я планировал закончить на какой-то красивой цифре следующий шаг #7 я закончу тем, что опишу все что получилось в результате доработок. А доработки будут следующими:

  1. для того чтобы не плодить мелкие кастомные классы, состоящие из одной строки, подобные тому что были раньше для вьюеров и появились сейчас для форм, на базе конфигурации основного класса CommonGrid я создам конфигурацию для всех его дочерних компонентов - окон, вкладок, форм и т.п.
  2. чтобы не таскать эту конфигурацию через длинные цепочки контролов, которые сами порождают другие контролы , я создам что-то типа своего менеджера контролов - отдельное хранилище для всех конфигураций и буду при необходимости извлекать из него нужную информацию.
  3. придам приложению товарный вид
  4. доделаю меню групповых операций хотя бы для удаления записей
  1. 2012-04-24
  2. ExtJS-large-application
Go Index Test