Пример. Дерево, по клику на ноде создается tab с гридой.
За отображение и заполнение дерева отвечают:
mainwin/spr-main-win.js
mainwin/spr-main-tree.php
За отображение гриды
mainwin/grid-class-vdoc.js
mainwin/model-vdoc.php
Интерфейс состоит из одного окна (window), в котором на западе растет дерево, в центре tab panel. На дереве поставлен listener, который обрабатывает событие on click - добавляется новая tab panel.
За добавление панелей отвечает функция
function addTab(index, title) {
В зависимости от наименования ноды (свойство title) выбирается тип гриды, которую мы создали и зарегистрировали (пример код ниже grid-class-vdoc.js )
if (title == 'Тип документа') {gridxtype = 'tdocgrid'};
if (title == 'Вид документа') {gridxtype = 'vdocgrid'};
Проверяем, что такая вкладка отсутствует
if (gridxtype !='') {
if (!tabs.findById(title)) {
Добавляем новую панель
var tab = tabs.add({
id: title,
title: title,
iconCls: 'icon-tab',
bodyStyle: 'padding: 5px',
xtype: gridxtype, //'tdocgrid', // тип определен в grid-class-tdoc
closable: true
}); // eo tabs add
//console.info(tab.id);
tab.show();
} else {
tabs.setActiveTab(tabs.findById(title));
} // eo find уже есть такая вкладка
} // вообще такой тип вкладки описан
}; // eo funct addTab
Для того, чтобы на вкладке появился наш грид, мы предварительно создаем классы-расширения, регистрируем их как новый тип, а потом лениво (lazy) используем
Т.е. создаем, регистрируем
grid-class-vdoc.js
Vdoc.Grid = Ext.extend(Ext.grid.GridPanel, { ... // создаем новое расширение
Ext.reg('vdocgrid', Vdoc.Grid); // регистрируем наш класс для дальнейшего использования
Используем зарегистрированный тип
spr-main-win.js
var tab = tabs.add({...
xtype: 'vdocgrid', ...
listing mainwin/spr-main-win.js
/**
* Дерево справочников с табами и гридами
*/
Ext.onReady(function(){
// загружает дерево
var treeLoader = new Ext.tree.TreeLoader({
dataUrl:'spr-main-tree.php' // серверный код, который будет строить дерево
});
// корневая ветка
var rootNode = new Ext.tree.AsyncTreeNode({
text: 'Справочники'
, draggable: false
, id: '1' // id по умолчанию
});
// обычная модель выбора
var smodel = new Ext.tree.DefaultSelectionModel;
// на западе будет расти дерево
var tree = new Ext.tree.TreePanel({
title: 'Список',
region: 'west',
split: true,
width: 200,
collapsible: true,
margins:'3 0 3 3',
cmargins:'3 3 3 3',
//renderTo:'treecontainer',
loader: treeLoader,
root: rootNode,
rootVisible: true,
selModel: smodel
});
// В центре - tab panel
var tabs = new Ext.TabPanel({
region: 'center',
margins:'3 3 3 0',
activeTab: 0,
defaults:{autoScroll:true}
});
// главное окно
var win = new Ext.Window({
title: 'Справочники',
closable:true,
collapsible: true,
maximizable: true,
width:1000,
height:350,
//border:false,
plain:true,
layout: 'border',
items: [tree, tabs] // дерево и панель закладок
});
//*************** функции **************************
function addTab(index, title) {
gridxtype = '';
if (title == 'Тип документа') {gridxtype = 'tdocgrid'};
if (title == 'Вид документа') {gridxtype = 'vdocgrid'};
//console.info(gridxtype);
// проверяем что такая вкладка отсутствует и ее тип "Тип документа"
if (gridxtype !='') {
if (!tabs.findById(title)) {
var tab = tabs.add({
id: title,
title: title,
iconCls: 'icon-tab',
bodyStyle: 'padding: 5px',
xtype: gridxtype, //'tdocgrid', // тип определен в grid-class-Xdoc
closable: true
}); // eo tabs add
//console.info(tab.id);
tab.show();
} else {
tabs.setActiveTab(tabs.findById(title));
} // eo find уже есть такая вкладка
} // вообще такой тип вкладки описан
}; // eo funct addTab
// ************ события ****************************
tree.on('click', function(node) {
addTab(0,node.attributes.text);
});
// выбор ветки
//tree.selModel.on('selectionchange', function(selModel, node) {
// Ext.Msg.alert(node.attributes.text);
//});
win.show(this);
});
/**
* Класс-расширение для грида "вид документов"
mainwin/grid-class-vdoc.js
*/
// namespace
Ext.ns('Vdoc');
Ext.BLANK_IMAGE_URL = '../../lib/extjs/resources/images/default/s.gif';
Vdoc.Grid = Ext.extend(Ext.grid.GridPanel, {
initComponent: function(){
var config = {
store: new Ext.data.JsonStore({
id: 'ID',
totalProperty: 'total',
successProperty: 'success',
root: 'tablerow',
url: 'model-vdoc.php', // серверный код, который будет загружать данные в грид
autoLoad: false,
fields: [
{name: 'ID', type: 'string', mapping: 'ID'}
,{name: 'vdoc', type: 'string', mapping: 'VDOC'}
,{name: 'namedoc', type: 'string', mapping: 'NAMEDOC'}
]
}),
columns: [
{
id: 'ID',
header: 'PK',
dataIndex: 'ID',
width: 70,
hidden : true
}, {
header: 'Вид документа', dataIndex: 'namedoc',
width: 200, hidden : false
}, {
header: 'Вид', dataIndex: 'vdoc',
width: 90, hidden : false
}
],
viewConfig: {
forceFit: true
},
loadMask: true
}; // eo config object
// apply config
Ext.apply(this, Ext.apply(this.initialConfig, config));
// нижняя панель с листалкой PagingToolbar
this.bbar = new Ext.PagingToolbar({
store: this.store,
displayInfo: true,
pageSize: 10
});
// родитель
Vdoc.Grid.superclass.initComponent.apply(this, arguments);
// грузим store
this.on({
afterlayout: {
scope: this,
single: true,
fn: function(){
// !!! Здесь грузим хранилище store
this.store.load({
params: {start: 0,limit: 10}
});
}
}
});
} // eo function initComponent
,
afterRender: function(){
Vdoc.Grid.superclass.afterRender.apply(this, arguments);
...
} // eo function afterRender
});
// регистрируем наш класс для дальнейшего использования
Ext.reg('vdocgrid', Vdoc.Grid);
//********************* Серверный код ***********************//
Код, который строит дерево
Данные для дерева сервер отправляет в таком виде
Данные для дерева сервер отправляет в таком виде
[{"id":2,"text":"Тип документа","leaf":true},{"id":3,"text":"Вид документа","leaf":true},{"id":4,"text":"КБК","leaf":true}]
<?php
/* Дерево - меню для отображения наименований справочников */
$host="127.0.0.1:C:/Apache/www/BD/PUBOB.FDB";
$username="SYSDBA";
$password="masterkey";
$errmsg = '';
$stmt = 'select ID, TEXT from TREE_SPRAV where PARENTID =';
$parent_id = isset($_POST['node']) ? $_POST['node'] : 1;
///************** соединение **************************
$dbh = @ibase_connect($host, $username, $password);
if ($dbh == FALSE)
{
$errmsg = 'Ошибка соединения '. ibase_errormsg();
//echo $errmsg;
}
$out = GetTree($dbh, $stmt, $parent_id);
ibase_close($dbh);
echo $out;
// получить дерево начиная с ветки $parent_id
function GetTree($dbh, $stmt, $parent_id) {
$stmt_node = $stmt. $parent_id;
//$stmt = 'select ID, TEXT from TREE_SPRAV where PARENTID =1';
//echo $stmt;
$dst = @ibase_query($dbh, $stmt_node); // выполняем запрос
if ($dst == FALSE)
{
$errmsg = 'Ошибка выполнения '. ibase_errmsg();
echo $errmsg;
}
$json_dst = '';
while ($row = ibase_fetch_object($dst)) {
//echo $row->ID . "\n";
$node['id']= $row->ID;
$node['text']= $row->TEXT;
// проверяем есть ли у этой ветки потомки
$stmt_child = $stmt. $row->ID;
$dst_child = ibase_query($dbh, $stmt_child);
$row_child = ibase_fetch_assoc($dst_child);
// если потомков нет - это лист (leaf)
$node['leaf'] = count($row_child) > 1 ? false : true;
$result[] = $node; // добавляем ноду к массиву результат
} // eo while
ibase_free_result($dst);
return json_encode($result);
}; // eo funct
?>
Таблица с данными
CREATE TABLE TREE_SPRAV (
ID INTEGER NOT NULL,
TEXT VARCHAR(150),
PARENTID INTEGER
);
Часть серверного кода, отвечающего за заполнение гриды
В таком виде сервер отправляет данные
$out ='{ "success": true,"total": 9, "tablerow":[ {"ID":1,"TDOC":1,"NAMETDOC":"name tdoc 1"} , {"ID":2,"TDOC":2,"NAMETDOC":"name 2"}]}';
$dbh - соединение ($dbh = ibase_connect($host, $username, $password);)
$stmt - Запрос для выбора данных
$stmt = 'select '
.' ID, VDOC, NAMEDOC from SPR_VDOC '
. ' [ORDER] [ROWS] ';
$stmtcount - Запрос для подсчета количества записей
$stmtcount = "select count(*) as rccount from SPR_VDOC ";
Вариант, который проще для восприятия.
function getRecords($dbh, $stmt, $stmtcount, $sort, $dir, $start, $limit) {
// всего записей
$record_count = getRecordCount($dbh, $stmtcount);
// строим строчку для select rows 1 to 10
$fetch_limit = "";
// проверка сортировки и dir
if ((!strlen($sort) == 0) && (in_array(strtoupper($sort), $fields_array))
&& (in_array($dir, array('ASC', 'DESC'))))
{$sort = ' order by '.$sort .' '. $dir;}
// page с.. по..
if (($start >= 0) && ($limit>0)){
if ($start ==0) {$start=1;}
$limit = $start + $limit;
$fetch_limit = ' rows ' . ($start) . ' to '.$limit ;
}
$stmt = str_replace('[ORDER]',$sort, $stmt);
$stmt = str_replace('[ROWS]',$fetch_limit, $stmt);
$dst = @ibase_query($dbh, $stmt); // выполняем запрос
if ($dst == FALSE)
{
$errmsg = 'Ошибка выполнения '. ibase_errmsg();
}
$json_dst = '';
while($row = ibase_fetch_assoc($dst)) {
// собираем строки
if ($json_dst == '') {
$json_dst = json_encode($row);
} else {
$json_dst .= ' , '.json_encode($row);
}
} // eo while
// вот такая строка у нас должна получиться
$json_dst = '{"success": true,"total": '.$record_count.', "tablerow":[ '.$json_dst.']}';
ibase_free_result($dst);
return $json_dst; // возвращаем данные в формате json
}
А это часть класса, который делает тоже самое, что и только код немного изменен
function getRecords($stmt, $stmtcount, $sort, $dir, $start, $limit, $filters){
// получить количество записей
$record_count = self::getRecordCount($stmtcount);
// строим строчку для select rows 1 to 10
$fetch_limit = "";
// проверка сортировки и dir
if ((!strlen($sort) == 0) && (in_array(strtoupper($sort), $fields_array))
&& (in_array($dir, array('ASC', 'DESC'))))
{$sort = ' order by '.$sort .' '. $dir;}
// page с.. по..
if (($start >= 0) && ($limit>0)){
if ($start ==0) {$start=1;}
$limit = $start + $limit;
$fetch_limit = ' rows ' . ($start) . ' to '.$limit ;
}
$stmt = str_replace('[ORDER]',$sort, $stmt);
$stmt = str_replace('[ROWS]',$fetch_limit, $stmt);
$stmt = str_replace('[WHERE]',$restrict, $stmt);
$dst = @ibase_query(self::$dbh, $stmt); // выполняем запрос
if ($dst == FALSE)
{
$errmsg = 'Ошибка выполнения '. ibase_errmsg();
}
$json_dst = '';
$rows = array();
while($row = ibase_fetch_assoc($dst)) {
$rows = array_merge($rows, array($row));
} // eo while
$rows = array('tablerow' => $rows);
$meta = array('metaData' => $meta);
$arr_out = $meta + array('success' => "true", "total" => $record_count) + $rows;
ibase_free_result($dst);
return json_encode($arr_out); // возвращаем данные в формате json
} // eo function getRecordsWithMetadata