Показаны сообщения с ярлыком Ext.Учебник.Таблицы PHP SQL. Показать все сообщения
Показаны сообщения с ярлыком Ext.Учебник.Таблицы PHP SQL. Показать все сообщения

понедельник, 8 декабря 2008 г.

Учебник: Grid PHP SQL Часть 12

Создание контекстного меню (правой кнопки)

Это будет последняя часть учебника!!! Знаю, знаю... было очень весело читать! Ок, достаточно! Теперь мы поговорим о контекстных меню или как их обычно называют меню открывающиеся по правому клику мышки.

Во-первых мы записываем номер ряда, на котором мы нажали:

var PresidentListingSelectedRow;


У нас будет простое меню с тремя пунктами: изменение текущей записи, удаление и печать таблицы.
Ок, давайте определим четыре функции. Первая будет вызываться каждый раз при нажатии правой кнопки мыши на таблице:

  function onPresidentListingEditorGridContextMenu(grid, rowIndex, e) {
e.stopEvent();
var coords = e.getXY();
PresidentListingContextMenu.rowRecord = grid.store.getAt(rowIndex);
grid.selModel.selectRow(rowIndex);
PresidentListingSelectedRow=rowIndex;
PresidentListingContextMenu.showAt([coords[0], coords[1]]);
}


Ок, как вы видите мы показываем переменную названную PresidentListingContextMenu. Мы ее еще не создали, мы сделаем это сразу после этого. Давайте определим три функции которые будут вызываться для каждого пункта меню:

  function modifyPresidentContextMenu(){
PresidentListingEditorGrid.startEditing(PresidentListingSelectedRow,1);
}

function deletePresidentContextMenu(){
confirmDeletePresidents();
}

function printListingContextMenu(){
printListing();
}


Как видите, это те функции, которые мы уже определили. Ок, давайте определим ContextMenu:
  PresidentListingContextMenu = new Ext.menu.Menu({
id: 'PresidentListingEditorGridContextMenu',
items: [
{ text: 'Modify this President', handler: modifyPresidentContextMenu },
{ text: 'Delete this President', handler: deletePresidentContextMenu },
'-',
{ text: 'Print this grid', handler: printListingContextMenu }
]
});


Последнее, что нам понадобится это перехватчик событий (actionlistener) который будет вызывать функцию onPresidentListingEditorGridContextMenu при нажатии правой кнопки (я пытался найти еще более длинное имя для этой функции, но... :))
  PresidentListingEditorGrid.addListener('rowcontextmenu', onPresidentListingEditorGridContextMenu);


Это конец учебника. Надеюсь он помог вам понять как работать с таблицами в ext. Теперь вы понимаете ее код. Не забывайте проверять наши материалы и играйте с различными методами, свойствами и событиями.

Вы можете оставить отзыв на форуме http://extjs.com/forum/showthread.php?p=144865#post144865
For more advanced features and usage of grids, I want to once again refer you to Michael Lecomte's tutorial.
Для более продвинутых функций таблиц посмотрите учебник Michael Lecomte's
Happy Griding!http://extjs.com/learn/Tutorial:Ext20_Grid_Editor_PHP_MySQL


Nicolas Bize.

Что запомнить из этой части

* Перехватчик событий необходимо прикреплять к таблице
* Вам не надо пересоздавать контекстное меню каждый раз заново, так как это глобальная переменная :)

Материалы этой части можно скачать по ссылке http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%2012.zip

Учебник: Grid PHP SQL Часть 11

Печать вашей таблицы.

Отлично... Я собираюсь сказать одну вещь до того, как буду заспамлен тоннами писем с критикой... Метод, описанный здесь для печати вашей таблицы не единственно возможный и не самый оригинальный. Это просто быстрый пример того, как можно распечатать таблицу.

Наш метод - это просто создание HTML файла и заполнение его массивом, содержащим отображаемые в таблице данные (все данные, не только 15 выведенных в данный момент)

Во-первых, мы добавим кнопку Print на нашу панель инструментов:


         ,'-', {
text: 'Print',
tooltip: 'Print me!',
handler: printListing,
iconCls:'print' // defined in our css
}


Давайте теперь определим функцию printListing(). Эта функция вызовет php функцию которая создаст HTML файл таблицы:

    function printListing(){
var searchquery = "";
var searchfirstname = "";
var searchlastname = "";
var searchparty = "";
var searchenteringoffice = "";
var searchleavingoffice = "";
var win; // our popup window
// check if we do have some search data...
if(PresidentsDataStore.baseParams.query!==null){searchquery = PresidentsDataStore.baseParams.query;}
if(PresidentsDataStore.baseParams.firstname!==null){searchfirstname = PresidentsDataStore.baseParams.firstname;}
if(PresidentsDataStore.baseParams.lastname!==null){searchlastname = PresidentsDataStore.baseParams.lastname;}
if(PresidentsDataStore.baseParams.party!==null){searchparty = PresidentsDataStore.baseParams.party;}
if(PresidentsDataStore.baseParams.enteringoffice!==null){searchenteringoffice = PresidentsDataStore.baseParams.enteringoffice;}
if(PresidentsDataStore.baseParams.leavingoffice!==null){searchleavingoffice = PresidentsDataStore.baseParams.leavingoffice;}

Ext.Ajax.request({
waitMsg: 'Please Wait...',
url: 'database.php',
params: {
task: "PRINT",
// we have to send all of the search

query: searchquery, // if we are doing a quicksearch, use this
firstname : searchfirstname, // if we are doing advanced search, use this
lastname : searchlastname,
party : searchparty,
enteringoffice : searchenteringoffice,
leavingoffice : searchleavingoffice,
currentlisting: PresidentsDataStore.baseParams.task // this tells us if we are searching or not
},
success: function(response){
var result=eval(response.responseText);
switch(result){
case 1:
win = window.open('./presidentslist.html','presidentslist','height=400,width=600,resizable=1,scrollbars=1, menubar=1');
win.print();
break;
default:
Ext.MessageBox.alert('Uh hu...','Unable to print the grid!');
break;
}
},
failure: function(response){
var result=response.responseText;
Ext.MessageBox.alert('error','could not connect to the database. retry later');
}
});
}


Ок, вы можете удивится почему мы должны передавать так много параметров... Дело в том что... мы хотим распечатать всю нашу таблицу а наш DataStore содержит лишь 15 записей. Поэтому наш PHP файл собирается сделать запросы заново еще раз. не ограничивая поиск частичными запросами. Затем наш database.php сложит все это в файл listpresidents.html.

Вот наш database.php файл (сначала выбор)
    case "PRINT":
printPresidents();
break;


А затем функция печати:
function printPresidents()
{
// Ok since we limited our queries to 15 entries, we need to do a query again and get everything.
if($_POST['currentlisting']=='LISTING'){ // we are doing a basic listing or using the quicksearch
$query = "SELECT * FROM presidents pr, parties pa WHERE pr.IDparty = pa.IDparty";
// Here we check if we have a query parameter :
if (isset($_POST['query']) && ($_POST['query'] != "")){
$query .= " AND (pr.firstname LIKE '%".$_POST['query']."%' OR pr.lastname LIKE '%".$_POST['query']."%')";
}
$query .= " ORDER BY tookoffice";
$result = mysql_query($query);
$nbrows = mysql_num_rows($result);
} else if($_POST['currentlisting']=='SEARCH'){
$query = "SELECT * FROM presidents pr, parties pa WHERE pr.IDparty = pa.IDparty";
$firstname = $_POST['firstname'];
$lastname = $_POST['lastname'];
$enteringoffice = $_POST['enteringoffice'];
$leavingoffice = $_POST['leavingoffice'];
$party = $_POST['party'];

if($firstname != ''){
$query .= " AND firstname LIKE '%".$firstname."%'";
};
if($lastname != ''){
$query .= " AND lastname LIKE '%".$lastname."%'";
};
if($party != ''){
$query .= " AND pr.IDparty = '".$party."'";
};
if ($enteringoffice) {
$query .= " AND tookoffice >= '".$enteringoffice."'";
};
if ($leavingoffice) {
$query .= " AND leftoffice <= '".$leavingoffice."'";
};
$result = mysql_query($query);
$nbrows = mysql_num_rows($result);
}

// We now have our array, let's build our HTML file :
$file = fopen("presidentslist.html",'w');
fwrite($file, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html xmlns='http://www.w3.org/1999/xhtml'><head><meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1' /><title>Printing the Grid</title><link rel='stylesheet' type='text/css' href='printstyle.css'/></head>");
fwrite($file, "<body><table summary='Presidents List'><caption>The Presidents of the United States</caption><thead><tr><th scope='col'>First Name</th><th scope='col'>Last Name</th><th scope='col'>Party</th><th scope='col'>Entering Office</th><th scope='col'>Leaving Office</th><th scope='col'>Income</th></tr></thead><tfoot><tr><th scope='row'>Total</th><td colspan='4'>");
fwrite($file, $nbrows);
fwrite($file, " presidents</td></tr></tfoot><tbody>");
for($i = 0; $i< $nbrows; $i++){
$data = mysql_fetch_array($result);
fwrite($file,'<tr');
if($i%1==0){
fwrite($file," class='odd'");
}
fwrite($file, "><th scope='row' id='r97'>");
fwrite($file, $data['firstname']);
fwrite($file,"</th><td>");
fwrite($file, $data['lastname']);
fwrite($file, "</td><td>");
fwrite($file, $data['name']);
fwrite($file, "</td><td>");
fwrite($file, codeDate($data['tookoffice']));
fwrite($file, "</td><td>");
fwrite($file, codeDate($data['leftoffice']));
fwrite($file, "</td><td> $");
fwrite($file, $data['income']);
fwrite($file, "</td></tr>");
}
fwrite($file, "</tbody></table></body></html>");
fclose($file);
echo '1'; // we are done.

}


На самом деле это очень просто. Мы просто вставляем запросы без ограничения количества записей и сохраняет полученный массив в HTML файл. Затем мы возвращаем 1.
Как будут выглядеть результаты на самом деле зависит от вас!
Некоторые предпочитают решения на основе экспорта в PDF формат. Вы можете найти эту информацию в топиках форумов.

Что запомнить:
Этот способ нельзя применить везде
Он не показывает колонки в нужном выбранном порядке и видимости
Это не самое лучшее решение.

Файлы этой части можно скачать здесь http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%2011.zip

Учебник: Grid PHP SQL Часть 10

Компонент быстрого поиска.

Отлично... Мы почти прошли этот учебник!!! Скоро вы сможете создавать свои собственные впечатляющие таблицы. Давайте изучим компонет QuickSearch.
Мы уже прошли тему как осуществлять обычный поиск по таблице. Для этого нужно чтобы пользователь нажал кнопку Search и ввел поля поиска... Ок, чтож, вы поймете что это может оказаться очень сложной задачей для большинства пользователей. И тут появляется мистер быстрый поиск QuickSearch. Компонент QuickSearch это просто текстовое поле в котором пользователь вводит текст для поиска, нажимает Ввод и тогда... А дальнейшее зависит от того как мы это сделаем..

Давайте продолжим и сделаем так ,чтобы текст искался всей таблице.
Отлично, до того как мы начнем нам нужно добавить еще один .js файл в заголовок HTML файла:
<script type="text/javascript" src="searchfield.js"></script>


Вы можете найти файл в папке examples/form архива extjs или скачайте его по ссылке http://extjs.com/deploy/dev/examples/form/SearchField.js
Во-первых мы просто добавим его на нашу панель инструментов. Нам просто надо установить некоторые основные параметры, которые передаем в datastore.
, '-', new Ext.app.SearchField({
store: PresidentsDataStore,
params: {start: 0, limit: 15},
width: 120
})


Ок, если вы достаточно опытны, мы можем просто открыть файл searchfield.js в любимом Блокноте и посмотреть что там внутри... И там вы увидите параметр называемый query который посылается при перезагрузке datastore. Да... Мы знаем что есть что! Теперь.. DataStore президентов может быть как в LISTING режиме так и в режиме SEARCHING (зависит от параметров). Итак, кнопка QuickSearch будет просто добавлять строку введенную в текстовое поле как дополнительный параметр.
Я просто собираюсь реализовать это при простом получении списка президентов. Я вам покажу как это сделать при поиске (быстрый поиск на существующем поиске)
Давайте откроем наш файл database.php.Теперь, когда мы обращаемся к функции getList() мы должны проверить нет ли у нас параметра query. И если есть мы должны найти похожие данные в нашей таблице. Теперь наша новая функци getList выглядит так:
  $query = "SELECT * FROM presidents pr, parties pa WHERE pr.IDparty = pa.IDparty";
// Here we check if we have a query parameter :
if (isset($_POST['query'])){
$query .= " AND (pr.firstname LIKE '%".addslashes($_POST['query'])."%' OR pr.lastname LIKE '%".addslashes($_POST['query'])."%')";
}
$result = mysql_query($query);
$nbrows = mysql_num_rows($result);
$start = (integer) (isset($_POST['start']) ? $_POST['start'] : $_GET['start']);
$end = (integer) (isset($_POST['limit']) ? $_POST['limit'] : $_GET['limit']);
$limit = $query." LIMIT ".$start.",".$end;
$result = mysql_query($limit);
[...]

Это так просто! :) Ну теперь вы можете брать параметр query, убрать все пробелы, разбить по словам для лучшего поиска. Вы даже можете делать поиск по годам и так далее... Реализация поиска, который мыуже сделали достаточно проста. Просто проверяйте переменную query до того, как сделаете запрос. Вот и все!

Скачать файлы проекта можно по ссылке http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%2010.zip

Учебник: Grid PHP SQL Часть 9

Панель страниц

Ну что, это снова вы... Да... Ок, давайте поговорим о панели страниц, которую вы можете увидеть внизу таблицы. Она мне всегда очень нравилась. Самое хорошее, что реализовать ее очень просто. Так давайте быстро сделаем ее!

Элемент PagingToolbar должен знать в основном две вещи: как много записей вы хотите отображать на странице и куда отсылать информацию о текущей странице.(мы будем посылать эту информацию в DataStore)
Итак... Сразу после панели инструментов в EditorGrid, давайте добавим нижнюю панель:
      bbar: new Ext.PagingToolbar({
pageSize: 15,
store: PresidentsDataStore,
displayInfo: true
})

Мы будем показывать по 15 президентов на странице. Мы уже почти все сделали! Единственная вещь теперь - как сообщить нашему PHP скрипту как мы будем делать наш постраничный просмотр. Элемент PagingToolbar использует два параметра - start (стартовая запись) и limit (количество записей). Они будут доступны в серверном скрипте и мы должны лишь только учесть их в нашем SQL запросе.
Давайте убедимся что посылаем эти параметры каждый раз, когда нам нужен список президентов: Каждую PresidentsDataStore.reload() или PresidentsDataStore.load() мы трансформируем в:
  PresidentsDataStore.reload({params: {start: 0, limit: 15}});

Сделайте изменения сами (они встречаются в mainscript.js) только в 3 местах)


Серверная часть
Это очень просто. Теперь, когда мы имеем переменные start и limit, нам нужно получить их значения и изменить конец нашего SQL запроса.
Вот изменения в фукции getList():
  $query = "SELECT * FROM presidents pr, parties pa WHERE pr.IDparty = pa.IDparty";
$result = mysql_query($query);
$nbrows = mysql_num_rows($result);
// Add this for the paging bar:
$start = (integer) (isset($_POST['start']) ? $_POST['start'] : $_GET['start']);
$end = (integer) (isset($_POST['limit']) ? $_POST['limit'] : $_GET['limit']);
$limit = $query." LIMIT ".$start.",".$end;
$result = mysql_query($limit);

Мы все еще хотим делать первый запрос так, чтбы получить общее количество записей (nbrows), но обратно в Ext будем отсылать массим содержащий 15 или менее записей, которые были запрошены.
Давайте не забудем сделать эти же изменения в функции поиска searchPresidents().

Файл с материалами этой части учебника здесь http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%209.zip

пятница, 5 декабря 2008 г.

Учебник: Grid PHP SQL Часть 8

Поиск по таблице

Отлично.. Как вы можете видеть мы может форматировать нашу таблицу так как захотим. Сегодня мы собираемся научиться как что-нибудь искать в таблице. Легко найти Джона Кеннеди, не потому конечно, что знаешь дату его избрания, но так же потому, что в нашей таблице всего 40 записей. Другое дело, если мы включили всех политиков США... Следовательно мы должны дать пользователю возможность сужать поиск.

Создание формы поиска

Когда мы создали форму мы объявили некоторые поля как глобальные переменные и работали с ними через методы name.setValue() или getValue(). Помните, что из-за этого мы можем иметь только одну форму для добавления записей. В нашем случае это не ограничивает ничего, а целью было сосредоточиться на табличной системе ext. Однако, чтобы показать как подобные вещи следует делать мы создадим следующую форму без глобальных переменных. Следовательно мы сможем открывать несколько форм поиска одновременно. Это очень полезно в наши дни.
Вот как мы сделаем. Когда мы наживаем на кнопку Advanced Search (Расширенный поиск) мы хотим, чтобы открылось новое окно для поиска с пустыми полями и готовое для поиска. Мы бы хотели сделать окно с расширенным поиском по нескольким полям.

Сначала, довайте добавим кнопку поиска Search в панель инструментов (в PresidentListingEditorGrid):
          }, '-', {
text: 'Search',
tooltip: 'Advanced Search',
handler: startAdvancedSearch, // search function
iconCls:'search' // we'll need to add this to our css
}

Давайте определим нашу функцию startAdvancedSearch. Вот немного для начала:
  function startAdvancedSearch(){
// local vars
var PresidentSearchForm;
var PresidentSearchWindow;
var SearchFirstNameItem;
var SearchLastNameItem;
var SearchPartyItem;
var SearchEnteringItem;
var SearchLeavingItem;

SearchFirstNameItem = new Ext.form.TextField({
fieldLabel: 'First Name',
maxLength: 20,
anchor : '95%',
maskRe: /([a-zA-Z0-9\s]+)$/
});

SearchLastNameItem = new Ext.form.TextField({
fieldLabel: 'Last Name',
maxLength: 20,
anchor : '95%',
maskRe: /([a-zA-Z0-9\s]+)$/
});

SearchPartyItem = new Ext.form.ComboBox({
fieldLabel: 'Party',
store:new Ext.data.SimpleStore({
fields:['partyValue', 'partyName'],
data: [['1','No Party'],['2','Federalist'],['3','Democratic-Republican'],['4','Democratic'],['5','Whig'],['6','Republican']]
}),
mode: 'local',
displayField: 'partyName',
valueField: 'partyValue',
anchor:'95%',
triggerAction: 'all'
});

SearchEnteringItem = new Ext.form.DateField({
fieldLabel: 'Entered Office after',
format : 'm/d/Y',
anchor:'95%'
});

SearchLeavingItem = new Ext.form.DateField({
fieldLabel: 'Left Office before',
format : 'm/d/Y',
anchor:'95%'
});
}

Знакомо выглядит? Так и должно быть!!! Это почти тоже самое что мы делали при создании формы.. За исключеним того, что мы не указываем никакие идентификаторы (запомните, что они должны быть уникальны, мы не можем иметь несколько элементов с одинаковыми id) Другое огромное отличие в том, что каждое поле, форма или окно определено прямо в функции. Нам не нужно беспокоится о скрытии окна, мы просто можем открыть другое окно как только это закроется.
Продолжим:
     PresidentSearchForm = new Ext.FormPanel({
labelAlign: 'top',
bodyStyle: 'padding: 5px',
width: 300,
items: [{
layout: 'form',
border: false,
items: [ SearchFirstNameItem,SearchLastNameItem,SearchPartyItem,SearchEnteringItem, SearchLeavingItem ],
buttons: [{
text: 'Search',
handler: listSearch
},{
text: 'Close',
handler: resetSearch
}]
}]
});

PresidentSearchWindow = new Ext.Window({
title: 'President Search',
closable:true,
width: 200,
height: 400,
plain:true,
layout: 'fit',
items: PresidentSearchForm
});


Важный момент в этом коде - просто вызовы двух функций, listSearch и resetSearch, которые должны быть определены здесь же локально (смотри следующий параграф) чтобы позволить им получить доступ к локальным значениям полей. У нас есть кнопки Search (искать) и Close (закрыть). Кнопка Search будет запускать поиск а кнопка Close, то очень интересно, также будет выполнять поиск. Вот почему...
    function listSearch(){
// render according to a SQL date format.
var startDate = "";
var endDate = "";
if(SearchEnteringItem.getValue() != "") {
startDate = SearchEnteringItem.getValue().format('Y-m-d');
}
if(SearchLeavingItem.getValue() != "") {
endDate = SearchLeavingItem.getValue().format('Y-m-d');
}

// change the store parameters
PresidentsDataStore.baseParams = {
task: 'SEARCH',
firstname: SearchFirstNameItem.getValue(),
lastname : SearchLastNameItem.getValue(),
party : SearchPartyItem.getValue(),
enteringoffice : startDate,
leavingoffice : endDate
};
// Cause the datastore to do another query :
PresidentsDataStore.reload();
}

function resetSearch(){
// reset the store parameters
PresidentsDataStore.baseParams = {
task: 'LISTING'
};
// Cause the datastore to do another query :
PresidentsDataStore.reload();
PresidentSearchWindow.close();
}

// once all is done, show the search window
PresidentSearchWindow.show();

Видите почему? Все что мы делаем это берем оригинальный datastore и изменяем его параметры. Мы затем просим его перезагрузится. А это выполняет новый запрос. Результаты затем отображаются так же как и в начале учебника.
Это объясняет функцию resetSearch. Чтобы сбросить поиск, мы должны установить оригинальные параметры DataStore (а это просто задача listing). Затем мы перезагружаем наш DataStore.

Маленькое упражнение с запросами
Вы уже использовали эти Ajax запросы? Серверный скрипт просто обрабатывает это вызов как любой другой... Давайте запишем ( в database.php)

Сначала в выборе :
    case "SEARCH":
searchPresidents();
break;


а затем идет наша функция searchPresidents()
function searchPresidents()
{
$query = "SELECT * FROM presidents pr, parties pa WHERE pr.IDparty = pa.IDparty";

$firstname = $_POST['firstname'];
$lastname = $_POST['lastname'];
$enteringoffice = $_POST['enteringoffice'];
$leavingoffice = $_POST['leavingoffice'];
$party = $_POST['party'];

if($firstname != ''){
$query .= " AND firstname LIKE '%".$firstname."%'";
};
if($lastname != ''){
$query .= " AND lastname LIKE '%".$lastname."%'";
};
if($party != ''){
$query .= " AND pr.IDparty = '".$party."'";
};
if ($enteringoffice) {
$query .= " AND tookoffice >= '".$enteringoffice."'";
};
if ($leavingoffice) {
$query .= " AND leftoffice <= '".$leavingoffice."'";
};

$result = mysql_query($query);
$nbrows = mysql_num_rows($result);
if($nbrows>0){
while($rec = mysql_fetch_array($result)){
// render the right date format
$rec['tookoffice']=codeDate($rec['tookoffice']);
$rec['leftoffice']=codeDate($rec['leftoffice']);
$arr[] = $rec;
}
$jsonresult = JEncode($arr);
echo '({"total":"'.$nbrows.'","results":'.$jsonresult.'})';
} else {
echo '({"total":"0", "results":""})';
}
}

Итак мы рассмотрели простой поиск. И он работает достаточно хорошо. Теперь у вас может быть сотни записей а найти любую из них вы сможете очень быстро.

Что запомнить из этой части:
id обьектов должны быть уникальны
Работа с параметрами DataStore

Файлы этой части можно скачать здесь

Источник: http://extjs.com/learn/w/index.php?title=Tutorial:Grid_PHP_SQL_Part8

Учебник: Grid PHP SQL Часть 7

Настраиваемые CSS стили

Отлично, рад видеть, что вы все еще со мной! Если вы зашли так далеко, то вы уже наверное обладаете знаниями о редактировании, добавлении и удалении записей в таблице. Вы наверное провели часы, играясь с таблицей и потратили много времени, показывая свои достижения детям, супруге, родителям а может даже своей собаке. Наиболее вероятно, они ответили: "Отлично! Но есть ли вариант изменить css стиль вот тех ячеек??" Чтож, звучит загадочно.. ЭТО ВОЗМОЖНО! И... это на самом деле не очень сложно...

Давайте начнем сначала

В каждую колонку, добавленную в ColumnModel, мы можем добавить параметр, называемый renderer (построитель). Этот параметр просто функция, которая позволяет нам сказать Ext как отображать ячейки в этой колонке.
Функция постройки имеет 6 параметров: (data (данные), cell (ячейка), rowIndex (индекс ряда), columnIndex (индекс колонки), store). Играя с этими значениями мы можем установить любой стиль в нужном месте. На самом деле, это почти то же самое, что мы уже сделали в нашем NumberField... (мы написали '$' прямо за значением)

Играем с цветами

Мы найдем президентов, которые имели больше всего голосов. Для этого мы изменим цвет ячейки голосов в соответствии с её значением. Нам надо изменить функцию постройки колонки Income:
        renderer: function(value, cell){ 
var str = '';
if(value > 1000000){
str = "<span style='color:#336600;'>$ " + value + "</span>";
} else if (value > 100000 && value < 1000000){
str = "<span style='color:#FF9900;'>$ " + value + "</span>";
} else {
str = "<span style='color:#CC0000;'>$ " + value + "</span>";
}
return str;
},


Играем с css стилями

Вы наверное показывали вашу таблицу друзьям а те очень сердились, что не могут изменить идентификаторы ID президентов (эта колонка доступна для редактирования) и должно быть убили вашу мышку так, как будто играли в Diablo очень много времени. Давайте убережемся от таких друзей и изменим css стили ячеек. Это просто делается через cell.css поле.
Давайте добавим следующий код в style.css :
.readonlycell { 
background-color:#CCCCCC !important;
}


Теперь для IDPresident и IDParty давайте добавить построитель, который установит css стили для ячеек:
        renderer: function(value, cell){ 
cell.css = "readonlycell";
return value;
}


Запомните, функция построителя должна возвращать какие-то данные. Иначе вы не увидите ничего...

Любой стиль для любой ячейки
Как вы можете видеть, вы можете изменять ячейки так как захотите. В данном примере, мы изменили фоновое изображение для имени и фамилии президента. Просто так, без причины.. Я бы не советовар перегружать вашу таблицу большим количеством css стилей, так как иначе ваши глаза просто заболят, когда таблица появится на экране.

Что запомнить из этой части:
Используйте css стили лишь для того, чтобы было понятно и удобно работать с таблицой.

Файлы этой части можно скачать здесь

Источник: http://extjs.com/learn/w/index.php?title=Tutorial:Grid_PHP_SQL_Part7

Учебник: Grid PHP SQL Часть 6

Удаление записи

В предыдущих частях мы создали редактируемую таблицу с функцией добавления записей в нее. Давайте подумаем. Мы еще многое не реализовали, но уже написали пару сотен строк кода...
Это показывает насколько важно структурировать код. Есть множество топиков на форумах и учебников как правильно писать Ext код. Убедитесь, что используете Firefox и отладчик (Firebug) и проверяйте результаты в IE. Вы можете проверять ваши .js файлы с помощью JSLint чтобы убедится в их корректности. Очень легко потеряться в Ext коде, так как большинство структур построено в Json формате. Правильно расставляйте отступы. Если вам еще не понятно, посмотрите ЧАВО от Mickael's по таблицам.

Эта часть учебника научит нас удалять записи из таблицы. Это будет очень просто. Мы просто выбираем ряд таблицы и нажимаем кнопку Delete (Удалить), Ajax запрос посылается и трансформируется в SQL запрос, как мы делали в других случаях. Вы просто можете попробовать сделать это и посмотреть как это легко.

А что делать если мы хотим удалить несколько рядов. Как это сделать?? Вы можете выбирать носколько рядов с помощью CTRL или SHIFT.. Видите? Чтобы удалить все эти ряды мы должны их все обработать и мы это сделаем с помощью цикла и создадим массив который будет содержать все идентификаторы IDPresidents для каждого ряда. Затем мы просто перекодируем массив и отошлем его на сервер как параметр.

Давайте посмотрим, как это сделать:
  var selections = PresidentListingEditorGrid.selModel.getSelections();
var prez = [];
for(i = 0; i< PresidentListingEditorGrid.selModel.getCount(); i++){
prez.push(selections[i].json.IDpresident);
}
var encoded_array = Ext.encode(prez);

Как вы можете видеть этот код достаточно прямолинейный. Давайте внедрим его в наш скрипт.
Во-первых давайте добавим кнопку удаления на панель инструментов (мы также добавили CSS код), вот так:
  tbar: [
{
text: 'Add a President',
tooltip: 'Great tooltips...',
iconCls:'add', // reference to our css
handler: displayFormWindow
}, '-', {
text: 'Delete selection',
tooltip: 'Jose, can you seeeee??',
handler: confirmDeletePresidents, // Confirm before deleting
iconCls:'remove'
}]

Так как люди, которые будут использовать ваши приложения не всегда сообразительны (я не исключение) и могут просто нажать кнопку удаления случайно, нам нужно спросить подтверждение для удаления с помощью функции:
  function confirmDeletePresidents(){
if(PresidentListingEditorGrid.selModel.getCount() == 1) // only one president is selected here
{
Ext.MessageBox.confirm('Confirmation','Do you not like that president at all?', deletePresidents);
} else if(PresidentListingEditorGrid.selModel.getCount() > 1){
Ext.MessageBox.confirm('Confirmation','Delete those presidents?', deletePresidents);
} else {
Ext.MessageBox.alert('Uh oh...','You can\'t really delete something you haven\'t selected huh?');
}
}


Полная функция удаления

Итак, что мы имеем:
  function deletePresidents(btn){
if(btn=='yes'){
var selections = PresidentListingEditorGrid.selModel.getSelections();
var prez = [];
for(i = 0; i< PresidentListingEditorGrid.selModel.getCount(); i++){
prez.push(selections[i].json.IDpresident);
}
var encoded_array = Ext.encode(prez);
Ext.Ajax.request({
waitMsg: 'Please Wait',
url: 'database.php',
params: {
task: "DELETEPRES",
ids: encoded_array
},
success: function(response){
var result=eval(response.responseText);
switch(result){
case 1: // Success : simply reload
PresidentsDataStore.reload();
break;
default:
Ext.MessageBox.alert('Warning','Could not delete the entire selection.');
break;
}
},
failure: function(response){
var result=response.responseText;
Ext.MessageBox.alert('error','could not connect to the database. retry later');
}
});
}
}


Теперь подкорректируем серверный скрипт database.php:

Наши варианты выбора пополнятся:
    case "DELETEPRES":
deletePresidents();
break;

А теперь нам нужно реализовать функцию deletePresidents(). Эта небольшая часть, которая строит запрос взависимости от выбора. На не нужно делать столько же запросов, сколько нам нужно удалить записей. Мы должны сделать все удаления в одном запросе. (Firebug очень здесь поможет) В любом случаем запрос создается следующей функцией:
function deletePresidents(){
$ids = $_POST['ids']; // Get our array back and translate it :
if (version_compare(PHP_VERSION,"5.2","<")) {
require_once("./JSON.php");
$json = new Services_JSON();
$idpres = $json->decode(stripslashes($ids));
} else {
$idpres = json_decode(stripslashes($ids));
}

// You could do some checkups here and return '0' or other error consts.

// Make a single query to delete all of the presidents at the same time :
if(sizeof($idpres)<1){
echo '0';
} else if (sizeof($idpres) == 1){
$query = "DELETE FROM presidents WHERE IDpresident = ".$idpres[0];
mysql_query($query);
} else {
$query = "DELETE FROM presidents WHERE ";
for($i = 0; $i < sizeof($idpres); $i++){
$query = $query . "IDpresident = ".$idpres[$i];
if($i<sizeof($idpres)-1){
$query = $query . " OR ";
}
}
mysql_query($query);
}
// echo $query; This helps me find out what the heck is going on in Firebug...
echo '1';
}


Что надо запомнить из этой части:
SelectionModels
Firebug сохранит много вашего времени

Файлы этой части вы найдете здесь

Источник: http://extjs.com/learn/w/index.php?title=Tutorial:Grid_PHP_SQL_Part6

Учебник: Grid PHP SQL Часть 5

Добавление новой записи

Отлично, мы создали нашу таблицу и теперь даже можем вносить в нее изменения. Они записываются прямо в нашу SQL таблицу. Эта часть учебника научит вас добавлять новые записи в таблицу.

Есть много путей сделать это. Один из вариантов - это вставка пустой новой записи и ее редактирование. Это вариант, предпочитаемый M. LeCompte. Мы собираемся сделать это несколько другим способом. Мы создадим новое окно, которое будет содержать форму для заполнения данных президента.

Создание формы
Отлично, давайте посмотрим, какие поля формы нам понадобятся:
* Текстовое поле имени президента
* Текстовое поле фамилии
* Два поля даты - для ввода дат президентсва.
* Числовое поле для ввода поступлений
* Выпадающий список для партии

Все это надо поместить в форму и отобразить в окне. Давайте сделаем это вначале скрипта:
  var PresidentCreateForm;
var PresidentCreateWindow;

Чтобы каджому все было ясно и понятно мы будем создавать каждое поле до того, как добавлять его в форму. Каждое поле будет глобальной переменной (это не лучший вариант, позже вы сможете создавать различные идентификаторы для каждого поля и ссылаться на них) Просто запомните, вам бы не захотелось иметь 35078 глобальных переменных в программе... Также, почему мы делаем сейчас все таким способом - это защита от запуска двух форм одновременно.
Запомните: Если вы еще не ознакомились с нашей "подложкой" для кода приложения, позже вам лучше посмотреть учебник по Подложке (Структуре) Приложений сделаный Jozef Sakalos.
Давайте определим наши поля вначале скрипта:
  var FirstNameField;
var LastNameField;
var EnteringOfficeField;
var LeavingOfficeField;
var IncomeField;
var PartyField;

Нам нужно написать код который описывает назначения каждого поля: (внутри функции onReady):
  FirstNameField = new Ext.form.TextField({
id: 'FirstNameField',
fieldLabel: 'First Name',
maxLength: 20,
allowBlank: false,
anchor : '95%',
maskRe: /([a-zA-Z0-9\s]+)$/
});

LastNameField = new Ext.form.TextField({
id: 'LastNameField',
fieldLabel: 'Last Name',
maxLength: 20,
allowBlank: false,
anchor : '95%',
maskRe: /([a-zA-Z0-9\s]+)$/
});

EnteringOfficeField = new Ext.form.DateField({
id:'EnteringOfficeField',
fieldLabel: 'Entering Office',
format : 'm/d/Y',
allowBlank: false,
anchor:'95%'
});

LeavingOfficeField = new Ext.form.DateField({
id:'LeavingOfficeField',
fieldLabel: 'Leaving Office',
allowBlank: false,
format : 'm/d/Y',
anchor:'95%'
});

IncomeField = new Ext.form.NumberField({
id:'IncomeField',
fieldLabel: 'Income',
allowNegative: false,
allowBlank: false,
anchor:'95%'
});

Все очень просто и понятно. Теперь у нас есть поля... Вам нравится? Запомните, что поле должно быть связано с данными в SQL таблице. В 3 Части мы говорили об этом при использовании DataStore. В 4 части мы видим три различных варианта заполнения нашего выпадающего списка.
В этой части учебника мы продолжим использование SimpleStore. Вам следует держать в памяти, что заполнение нашего списка из предопределенного HTML списка может создать некоторые проблемы совместимости броузера (я подумал о бедных пользователях IE немножко...)
  PartyField = new Ext.form.ComboBox({
id:'PartyField',
fieldLabel: 'Party',
store:new Ext.data.SimpleStore({
fields:['partyValue', 'partyName'],
data: [['1','No Party'],['2','Federalist'],['3','Democratic-Republican'],['4','Democratic'],['5','Whig'],['6','Republican']]
}),
mode: 'local',
displayField: 'partyName',
allowBlank: false,
valueField: 'partyValue',
anchor:'95%',
triggerAction: 'all'
});


Создание формы

Теперь все поля созданы и готовы, надо создать форму для них:
  PresidentCreateForm = new Ext.FormPanel({
labelAlign: 'top',
bodyStyle:'padding:5px',
width: 600,
items: [{
layout:'column',
border:false,
items:[{
columnWidth:0.5,
layout: 'form',
border:false,
items: [FirstNameField, LastNameField, PartyField]
},{
columnWidth:0.5,
layout: 'form',
border:false,
items: [EnteringOfficeField, LeavingOfficeField, IncomeField]
}]
}],
buttons: [{
text: 'Save and Close',
handler: createThePresident
},{
text: 'Cancel',
handler: function(){
// because of the global vars, we can only instantiate one window... so let's just hide it.
PresidentCreateWindow.hide();
}
}]
});

PresidentCreateWindow= new Ext.Window({
id: 'PresidentCreateWindow',
title: 'Creating a New President',
closable:true,
width: 610,
height: 250,
plain:true,
layout: 'fit',
items: PresidentCreateForm
});


Ок... неплохо да? Недо запомнить одну важную вещь, то что каждый вложенный элемент имеет поле layout (подложка). Не забудьте его, так как это тема множества топиков на форумах... Ну хорошо, теперь у нас есть отличная форма. До того, как мы ее покажем, нам нужно перехватывать события кнопок и создать функции для каждого из них для сохранения данных. Хорошая штука в том, что мы так создали форму в том мы можем напрямую получать значения полей с помощью методов setValue() или getValue().

Давайте сначала создадим небольшие функции для работы с формой.
  // reset the Form before opening it
function resetPresidentForm(){
FirstNameField.setValue('');
LastNameField.setValue('');
EnteringOfficeField.setValue('');
LeavingOfficeField.setValue('');
IncomeField.setValue('');
PartyField.setValue('');
}

// check if the form is valid
function isPresidentFormValid(){
return(FirstNameField.isValid() && LastNameField.isValid() && EnteringOfficeField.isValid() && LeavingOfficeField.isValid() && IncomeField.isValid() && PartyField.isValid());
}

// display or bring forth the form
function displayFormWindow(){
if(!PresidentCreateWindow.isVisible()){
resetPresidentForm();
PresidentCreateWindow.show();
} else {
PresidentCreateWindow.toFront();
}
}


Создание президента
Теперь нам нужно реализовать метод сохранения. Вы найдете его достаточно простым по сравнению с тем, что мы делали при редактировании ячеек:
  function createThePresident(){
if(isPresidentFormValid()){
Ext.Ajax.request({
waitMsg: 'Please wait...',
url: 'database.php',
params: {
task: "CREATEPRES",
firstname: FirstNameField.getValue(),
lastname: LastNameField.getValue(),
enteringoffice: EnteringOfficeField.getValue().format('Y-m-d'),
leavingoffice: LeavingOfficeField.getValue().format('Y-m-d'),
income: IncomeField.getValue(),
party: PartyField.getValue()
},
success: function(response){
var result=eval(response.responseText);
switch(result){
case 1:
Ext.MessageBox.alert('Creation OK','The president was created successfully.');
PresidentsDataStore.reload();
PresidentCreateWindow.hide();
break;
default:
Ext.MessageBox.alert('Warning','Could not create the president.');
break;
}
},
failure: function(response){
var result=response.responseText;
Ext.MessageBox.alert('error','could not connect to the database. retry later');
}
});
} else {
Ext.MessageBox.alert('Warning', 'Your Form is not valid!');
}
}

Отлично... Это было неплохо, да? Теперь все что нам нужно это каким-нибудь образом вызывать displayFormWindow(). Мы можем делать это через контекстное меню (правый клик) который опишем позже, или мы можем сделать это с помощью панели инструментов. Давайте сделаем эту панель:
Нам просто нужно добавить следующее в наш конструктор EditorGrid:
      tbar: [{
text: 'Add a president',
tooltip: 'Great Tooltip',
iconCls:'add', // this is defined in our styles.css
handler: displayFormWindow
}]


Последние штрихи

Отлично. Мы еще не все сделали. Нам нужна серверная обработка запроса CREATEPRES.
Идем в файл database.php и вставим ее:
В выборе:
    case "CREATEPRES":
createPresident();
break;

И напишем саму функцию:
function createPresident(){

$firstname = addslashes($_POST['firstname']);
$lastname = addslashes($_POST['lastname']);
$enteringoffice = $_POST['enteringoffice'];
$leavingoffice = $_POST['leavingoffice'];
$income = $_POST['income'];
$party = $_POST['party'];

// Here we should probably do some database checking, to make sure that we do not have the same entry twice for ex... And we would return a different error code (ECHO '0' or whatever you want...) For now we'll pretend like the entry is valid.
$query = "INSERT INTO presidents (`IDpresident` ,`IDparty` ,`firstname` ,`lastname` ,`tookoffice` ,`leftoffice` ,`income` ) VALUES (NULL , '$party', '$firstname', '$lastname', '$enteringoffice', '$leavingoffice', '$income')";
$result = mysql_query($query);
echo '1';
}


Вот теперь вы можете добавлять президентов в вашу таблицу.

Что надо запомнить из этой части:
-Обязательно про SimpleStore

Файлы этой части учебника доступны здесь

Иточник: http://extjs.com/learn/Tutorial:Grid_PHP_SQL_Part5

Учебник: Grid PHP SQL Часть 4

Редактирование таблицы
Отлично, теперь у нас есть таблица отображающая материал. Вы уже можете увидесть все отличные возможности, которые предоставляет ext. Вы можете изменять или перемещать колонки. Вы можете решать, что показывать, а что нет. И самое лучшее, вы можете сделать маленькие красные треугольники в углах ячеек при редактировании.
Теперь вы спросите меня.Что на самом деле происходит когда я редактирую содержимое ячейки? Чтож, ответ достаточно простой... Ничего. Однако, Ext будет делать множество полезных вещей, он позволяет нам обрабатывать сохранение данных ,что означает... Это то что мы должны запрограммировать сами. Об этом и пойдет речь в этой части.

Ограничим некоторые поля.
До того, как мы двинемся вперед, есть одна вещь, которую нам нужно исправить. Как вы можете видеть в SQL таблицах, политические партии это предопределенный список (6 партий вобщем) и он не должен выходить за пределы этого списка.
Лучший путь реализовать это - изменить текстовое поле на выпадающий список в ColumnModel и задать ему различные свойства. Есть два простых варианта:
Вы можете создать новый DataStore который будет подключаться к database.php и запрашивать список партий для отображения. Просто подключите выпадающий список к этому DataStore и все сделано. Это особенно полезно, когда данные могут изменится за это время, но это не случай нашей программы.
Вы можете создать невидимый список в главном HTML файле и обновлять значения своего списка в соотетствии с этим. Это хороший подход, когда вы полностью уверены в статичности данных. Это делается через команду "transform".
Вы можете создать Simplestore, SimpleStore это DataStore который определен прямо в скрипте. Он затем доступен для изменения, но не подключен к прокси и не запрашивает никакие данные.
Теперь, это было бы очень хорошей практикой сделать все с помощью DataStore. Я уверен что это на самом деле вариант, который вы будете употребляять чаще всего и я бы посоветовал вам сделать это сейчас. В качестве маленькой подсказки я напишу изменения в ColumnModel, которые надо сделать.
{ 
header: 'Party',
dataIndex: 'Name',
width: 120,
editor: new Ext.form.ComboBox({
store: PartiesListingDataStore, // or whatever you've called it
displayField:'Name', // we have two indexes, ID and Name
typeAhead: true,
mode: 'remote',
triggerAction: 'all',
selectOnFocus:true
}),
hidden: false
}

Вы его получили? Отлично, тогда давайте перейдем к третьему варианту решения с помощью SimpleStore.

Нам понадобится хранилище, содержащее все наши статичные данные. Давайте сделаем его сейчас.
   header: 'Party',
dataIndex: 'PartyName',
width: 150,
editor: new Ext.form.ComboBox({
typeAhead: true,
triggerAction: 'all',
store:new Ext.data.SimpleStore({
fields:['partyValue', 'partyName'],
data: [['1','No Party'],['2','Federalist'],['3','Democratic-Republican'],['4','Democratic'],['5','Whig'],['6','Republican']]
}),
mode: 'local',
displayField: 'partyName',
valueField: 'partyValue',
listClass: 'x-combo-list-small'
})


Как вы можете видеть, мы можем определить какое поле отображать а какое поле использовать как значение. Теперь это выглядит привлекательно. Это означает что мы может напрямую посылать нашему PHP скрипту значение партии (IDparty) и нам не надо дополнительных запросов для этого.
Вот мы и сделали это. Испытайте его работу, вам понравится так, как будто вы только что попробовали вкусный шоколад.

Редактирование

И вот начинается сердце этой части... Как нам сохранять измененные внесения. Есть несколько путей решения этой проблемы...
Вы можете сохранять ряд каждый раз, как только какие то данные изменились. Это будет хорошо работать если у вас несколько независимых ячеек. Это не будет лучшим решеним, если вам надо сохранить много данных.
Вы можете пройтись циклом по таблице и лишь сохранить только те ячейки, которые были изменены в данной точке (регулярное автосохранение или кнопка для сохранения)
Вы можете просто сохранить всю таблицу в какое-то время.
Вы можете ничего не сохранять а пойти съесть чизбургер.
Выбор по-правде за вами, но это зависит от того, что надо сохранять в данный момент. Я не могу сказать что один метод луше чем другой...
Мы выберем первый вариант и будем сохранять президента каждый раз когда одна из этих ячеек изменяется. Мы сделаем это с помощью функции saveThePresident. Эта функция будет делать запрос к файлу database.php с видом задачи 'UPDATEPRES' и отсылать все данные строки. Затем она будет ожидать ответ от нашего серверного PHP скрипта. Все просто: database.php будет отсылать 1 если все сохранено удачно или 0 в другом случае. Если измение было успешно, мы просто перезагрузим наше хранилище и изменения автоматически отобразятся в таблице.
  function saveThePresident(oGrid_event){
Ext.Ajax.request({
waitMsg: 'Please wait...',
url: 'database.php',
params: {
task: "UPDATEPRES",
IDpresident: oGrid_event.record.data.IDpresident,
FirstName: oGrid_event.record.data.FirstName,
LastName: oGrid_event.record.data.LastName,
PartyName: oGrid_event.record.data.PartyName,
TookOffice: oGrid_event.record.data.TookOffice.format('Y-m-d'), // this time we'll format it thanks to ext
LeftOffice: oGrid_event.record.data.LeftOffice.format('Y-m-d'),
Income: oGrid_event.record.data.Income
},
success: function(response){
var result=eval(response.responseText);
switch(result){
case 1:
PresidentsDataStore.commitChanges(); // changes successful, get rid of the red triangles
PresidentsDataStore.reload(); // reload our datastore.
break;
default:
Ext.MessageBox.alert('Uh uh...','We couldn\'t save him...');
break;
}
},
failure: function(response){
var result=response.responseText;
Ext.MessageBox.alert('error','could not connect to the database. retry later');
}
});
}

Ок, теперь, когда наша функция готова нам нужно прикрепить ее к событию изменения содержимого ячейки пользователем.
Это делается в самом конце скрипта.
PresidentListingEditorGrid.on('afteredit', saveThePresident);

Запомните: место, где она будет вставлена неудачное. Я бы мог вставить эту строку в конструктор или сразу после того как моя таблица была создана.
Отлично, клиентская часть сделана. Теперь нам надо перейти к нашему серверу и исправить наш файл database.php file.
Сперва нам надо будет распознавать название задачи, поэтому добавим еще одно значение в список выбора:
    case "UPDATEPRES":
updatePresident();
break;

Этого недостаточно. Давайте напишем функцию updatePresident()
function updatePresident()
{
$IDpresident = $_POST['IDpresident'];
$FirstName = addslashes($_POST['FirstName']);
$LastName = addslashes($_POST['LastName']);
$PartyName = $_POST['PartyName'];
$TookOffice = $_POST['TookOffice'];
$LeftOffice = $_POST['LeftOffice'];
$Income = $_POST['Income'];

// First, find the $IDparty
$query = "SELECT IDParty FROM parties WHERE Name='".$PartyName."'";
$result = mysql_query($query);
if(mysql_num_rows($result)>0){
$arr = mysql_fetch_array($result);
$IDparty = $arr['IDParty'];
} else {
echo '0'; // failure
}

// Now update the president
$query = "UPDATE presidents SET firstname = '$FirstName', lastname = '$LastName', tookoffice = '$TookOffice', leftoffice =

'$LeftOffice', IDparty = '$IDparty', income='$Income' WHERE IDpresident=$IDpresident";
$result = mysql_query($query);
echo '1'; // success
}


Отлично, теперь протестируйте то что у нас получилось. Увидели как это работает? Нравиться?

Запомните: Мы просто сделали два запроса (хотя можно было бы сделать и с помощью одного - Догадалиь как?)
один - для получения IDparty для выбранной партии а другой запрос для самого изменения. Запомните, что эти запросы не проверяют ошибки при запросе.

Вы можете скачать файлы этого задания здесь

четверг, 4 декабря 2008 г.

Учебник: Grid PHP SQL Часть 3

Создание в Ext таблицы (Grid)

Отлично... Время отобразить наши результаты в прекрасной ext таблице... До этого ознакомимся с двумя вещами DataStores и ColumnModels.
Давайте начнем писать на файл mainscript.js :
var PresidentsDataStore;         // это будет наш datastore
var PresidentsColumnModel; // это будет columnmodel
var PresidentListingEditorGrid;
var PresidentListingWindow;

Ext.onReady(function(){
Ext.QuickTips.init();

DataStores
DataStore это массивы в которых хранятся данные (как вы уже наверное и сами догадались). Их назначение в том, чтобы получать данные из разных типов источников - от статических XML массивов до... динамических JSON источников!! Таблица (Grid) должна быть связана с DataStore. Если вы хотите изменить содержимое таблицы, вам в общем случае нужно изменить содержимое DataStore, а затем вызвать метод refresh().
Нам нужен DataStore которое будет подключяться к нашему файлу database.php, посылать задачу 'LISTING' и затем считывать результаты. Мы затем дадим соответствующие имена, которые сохранены в массие. Вот как мы построим простой DataStore:
  PresidentsDataStore = new Ext.data.Store({
id: 'PresidentsDataStore',
proxy: new Ext.data.HttpProxy({
url: 'database.php', // File to connect to
method: 'POST'
}),
baseParams:{task: "LISTING"}, // this parameter asks for listing
reader: new Ext.data.JsonReader({ // we tell the datastore where to get his data from
root: 'results',
totalProperty: 'total',
id: 'id'
},[
{name: 'IDpresident', type: 'int', mapping: 'IDpresident'},
{name: 'FirstName', type: 'string', mapping: 'firstname'},
{name: 'LastName', type: 'string', mapping: 'lastname'},
{name: 'IDparty', type: 'int', mapping: 'IDparty'},
{name: 'PartyName', type: 'string', mapping: 'name'},
{name: 'TookOffice', type: 'date', mapping: 'tookoffice'},
{name: 'LeftOffice', type: 'date', mapping: 'leftoffice'},
{name: 'Income', type: 'float', mapping: 'income'}
]),
sortInfo:{field: 'IDpresident', direction: "ASC"}
});

Ок, не так уж и сложно?

ColumnModels
Теперь нам нужно определить ColumnModel для нашей таблицы. Проще говоря, модель колонок указывает Ext то, как мы опеределили колонки таблицы. Будем мы отображать числа? Строки? Хотим ли мы сделать их редактируемыми? По факту, ColumnModel может делать гораздо больше чем мы обсудим в учебнике.

Теперь, мы просто отобразим основные колонки, как вы видите в следующем коде:
  PresidentsColumnModel = new Ext.grid.ColumnModel(
[{
header: '#',
readOnly: true,
dataIndex: 'IDpresident', // this is where the mapped name is important!
width: 50,
hidden: false
},{
header: 'First Name',
dataIndex: 'FirstName',
width: 150,
editor: new Ext.form.TextField({ // rules about editing
allowBlank: false,
maxLength: 20,
maskRe: /([a-zA-Z0-9\s]+)$/ // alphanumeric + spaces allowed
})
},{
header: 'Last Name',
dataIndex: 'LastName',
width: 150,
editor: new Ext.form.TextField({
allowBlank: false,
maxLength: 20,
maskRe: /([a-zA-Z0-9\s]+)$/
})
},{
header: 'ID party',
readOnly: true,
dataIndex: 'IDparty',
width: 50,
hidden: true // we don't necessarily want to see this...
},{
header: 'Party',
dataIndex: 'PartyName',
width: 150,
readOnly: true
},{
header: "Income",
dataIndex: 'Income',
width: 150,
renderer: function(v){ return '$ ' + v; }, // we tell Ext how to display the number
editor: new Ext.form.NumberField({
allowBlank: false,
decimalSeparator : ',',
allowDecimals: true,
allowNegative: false,
blankText: '0',
maxLength: 11
})
}]
);
PresidentsColumnModel.defaultSortable= true;


Часть, которую вы очень долго ждали.
Ок! Теперь, когда мы установили источник данных для чтения и настроили способ для отображения данных в таблице мы готовы создать саму таблицу!! Следующая часть кода - просто как кусок пирожного. Убедитесь, что не забыли вызвать load() в DataStore (load() запросит наш файл database.php):
  PresidentListingEditorGrid =  new Ext.grid.EditorGridPanel({
id: 'PresidentListingEditorGrid',
store: PresidentsDataStore, // the datastore is defined here
cm: PresidentsColumnModel, // the columnmodel is defined here
enableColLock:false,
clicksToEdit:1,
selModel: new Ext.grid.RowSelectionModel({singleSelect:false})
});

PresidentListingWindow = new Ext.Window({
id: 'PresidentListingWindow',
title: 'The Presidents of the USA',
closable:true,
width:700,
height:350,
plain:true,
layout: 'fit',
items: PresidentListingEditorGrid // We'll just put the grid in for now...
});

PresidentsDataStore.load(); // Load the data
PresidentListingWindow.show(); // Display our window

});


Что надо запомнить из этой части:
* Таблица должна иметь как datastore так и columnmodel для корректного отображения данных
* datastore необходимо перезагружать если в базе данных были сделаны изменения.

Материалы этой части можно скачать здесь

Источник: http://extjs.com/learn/Tutorial:Grid_PHP_SQL_Part3

Учебник:Grid PHP SQL Часть 2

Создание PHP / SQL обеспечения
SQL таблицы
Я предполагаю, что вы уже немного знаете о PHP и SQL. Постараюсь затронуть только основы в этом учебнике. Ок, давайте создадим несколько очень простых SQL таблиц! Мы собираемся создать маленькую историю США, мы будем иметь дело с различными президентами США. Я создал две таблицы, PRESIDENTS (президенты) и PARTIES (партии) и добавил одного президента. (остальных добавим позже).
Скачайте файл с SQL. Вам надо будет запустить его в базе данных, чтобы к началу работы таблицы уже были созданы.

JSON формат.
Перед началом работы с PHP файлом, вам нужно знать, что мы будем использовать формат JSON. Подробнее о нем вы можете посмотреть в википедии.. JSON - это способ форматирования данных, как тот же XML или CSV. За исключением того, что он намного компактнее чем XML.
Пример JSON:
{"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}

То же самое в XML будет выглядеть так:
<menu id="file" value="File">
<popup>
<menuitem value="New" onclick="CreateNewDoc()" />
<menuitem value="Open" onclick="OpenDoc()" />
<menuitem value="Close" onclick="CloseDoc()" />
</popup>

</menu>

И это сохраняет много места, спросите вы? Ну на самом деле это заметно на больших массивах данных... В любом случае, Ext понимает как JSON так и XML. Сейчас мы сконцентрируемся на JSON, так как большинство примеров, которые вы бы хотели увидеть будет использовать этот формат. Давайте запомним, что будем посылать форматированный в виде JSON массив нашему Ext скрипту. Мы сделаем это в нашем PHP файле с помощью функции JEncode().

PHP файл.

Ок, вот наш серверный скрипт. Давайте пройдемся по нему...
Во-первых серверу нужно подключится к базе данных. мы создадим очень простое подключение:
<?php
////////////////////////////////////////////////////////
// DATABASE.PHP
////////////////////////////////////////////////////////
mysql_connect("localhost", "username", "pwd") or
die("Could not connect: " . mysql_error());
mysql_select_db("db_name");


Вам нужно будет изменить имена компьютера, пользователя, пароль и имя базы данных на ваши.
Во-вторых нам нужно обрабатывать запросы от Ext. Мы будем из Ext передавать через $_POST в переменную "task" различные задачи. Итак, представьте что скрипт прислал на запрос в переменной $_POST['task'] и нам нужно его обработать.

  $task = '';
if ( isset($_POST['task'])){
$task = $_POST['task']; // получаем значение переменной из Ext
}
switch($task){
case "LISTING": // отдать весь список
getList();
break;
default:
echo "{failure:true}"; // простой 1-массив JSON - ответ : ошибка запроса.
break;
}

Отлично... Теперь, когда это сделано, давайте создадим функцию getList() которая будет посылать простой запрос нашей базе данных. Единственная проблема в том, что нам нужен для Ext формат JSON а SQL запрос возвращает массив. Итак, теперь мы должны представить скрипт, который будет конвертировать эти данные.
Ок, а вам это и не нужно делать... На самом деле в PHP версии 5.2 и выше эта функция уже реализована. Дааа... Но мы должны сделать так, чтобы скрипт работал на любой версии PHP, поэтому мы должны добавить файл JSON.php который будет осуществлять конвертирование для нас.

Отлично, возвращаемся к коду :
function getList() 
{
$query = "SELECT * FROM presidents pr, parties pa WHERE pr.IDparty = pa.IDparty";
$result = mysql_query($query);
$nbrows = mysql_num_rows($result);
if($nbrows>0){
while($rec = mysql_fetch_array($result)){
// render the right date format
$rec['tookoffice']=codeDate($rec['tookoffice']);
$rec['leftoffice']=codeDate($rec['leftoffice']);
$arr[] = $rec;
}
$jsonresult = JEncode($arr);
echo '({"total":"'.$nbrows.'","results":'.$jsonresult.'})';
} else {
echo '({"total":"0", "results":""})';
}
}

Как вы видите мы сложили все в большой массив $arr и передали его нашей JEncode() функции. Результат, $jsonresult - отличный JSON массив, готовый к отправке обратно скрипту Ext. Мы добавили количество записей и отправляем все обратно с помощью команды ECHO.
Запомните: Команда ECHO позволяет нам сделать отладку кода проще... Если вы знаете о чем я говорю, скачайте FIREBUG и используйте его по мере изучения учебника.
Кстати, мы добавили маленькую функцию codeDate которая просто преобразует формат даты из mm/dd/YYYY в YYYY-mm-dd формат. Мы сделали это для того чтобы напрямую посылать запрос к базе.
// Encodes a YYYY-MM-DD into a MM-DD-YYYY string
function codeDate ($date) {
$tab = explode ("-", $date);
$r = $tab[1]."/".$tab[2]."/".$tab[0];
return $r;
}

Ок, мы просто должны теперь написать функцию JEncode и все будет сделано!
function JEncode($arr){
if (version_compare(PHP_VERSION,"5.2","<"))
{
require_once("./JSON.php"); //if php<5.2 need JSON class
$json = new Services_JSON(); //instantiate new json object
$data=$json->encode($arr); //encode the data in json format
} else
{
$data = json_encode($arr); //encode the data in json format
}
return $data;
}
?>


Скачать сходные коды этой части учебника можно здесь

Источник: http://extjs.com/learn/Tutorial:Grid_PHP_SQL_Part2

Учебник: Grid PHP SQL Часть 1

Вступление
Этот учебник предназначен тем, для кого слова 'ColumnModel' или 'DataStore' звучат по-японски. Учебник проведет вас через основы построения таблицы в Ext со связью с PHP / SQL. Есть множество статей и форумов по этой теме. После больших собственных мучений при создании собственной рабочей таблицы и видя, что множество новичков все еще задаются этим вопросом в Ext, я решил выделить время и написал этот учебник.

Скриншоты
Вот изображение таблицы, которую мы построим.


Если ыв смотрите на эти картинки и говорите себе - "Классно!", значит этот учебник для вас.
В конце каждой части вы найдете ссылки на файлы для скачивания примера.

Источник: http://extjs.com/learn/Tutorial:Grid_PHP_SQL_Part1