WEB 2.0 программирование на Object Pascal. Часть 2

altКак я и обещал в прошлой первой части своей заметки, мы продолжим улучшать созданный нами пример. Сегодня мы добавим в наше приложение возможность создания, удаления, чтения и обновления информации.

Первым делом создадим панель инструментов и расположим на ней три кнопки: btnAdd, btnEdit и btnDelete. По их нажатию мы будем добавлять, редактировать и удалять данные. Кроме панели инструментов, нам также потребуется создать новое окно (popup window). В нем мы и будем управлять данными (добавлять/редактировать).

Новая таблица (grid)

Вместо того чтобы перезаписывать файлы, используемые в прошлом проекте, я рекомендую Вам создать новую директорию с именем samples2. В эту директорию Вы будете сохранять все рассмотренные примеры кода.

Обратите внимание: файл grid2.html содержит те же самые данные, что и файл grid1.html. Поэтому напарьтесь, а просто скопипастите этот файл в директорию sample2. Только не забудьте после копирования изменить имя с grid1.html на grid2.html. Проделав это не хитрое действие, измените также id контейнера с grid1 на grid2.

Содержимое файла grid2.js:

Ext.onReady(function(){
var dataStore = new Ext.data.JsonStore({
//url: ‘/samples/customerslist.json’,
url: ‘/cgi-bin/customerslist’,
root: ‘rows’,
method: ‘GET’,
fields: [
{name: ‘id’, type: ‘int’},
{name: ‘firstname’, type: ‘string’},
{name: ‘lastname’, type: ‘string’},
{name: ‘age’, type: ‘int’},
{name: ‘phone’, type: ‘string’}
]
});
var btnAdd = new Ext.Toolbar.Button({
text: ‘Add’,
handler: function(){
var win = new MyPeopleWindow();
// to refresh the grid after Insert
win.afterPost = function(){
dataStore.load();
};
win.show();
}
});
var btnEdit = new Ext.Toolbar.Button({
text: ‘Edit’,
handler: function(){
var win = new MyPeopleWindow(selRecordStore.id);
// to refresh the grid after Update
win.afterPost = function(){
dataStore.load();
};
win.show();
}
});
var btnDelete = new Ext.Toolbar.Button({
text: ‘Delete’,
handler: function(){
Ext.Msg.confirm(
‘Delete customer?’,
‘Are you sure to delete this customer?’,
function(btn){
if(btn == ‘yes’){
var conn = new Ext.data.Connection();
conn.request({
url: ‘/cgi-bin/customerslist’,
method: ‘POST’,
params: {«delete_person»: selRecordStore.id},
success: function(response, options) {
// refresh the grid after Delete
JSonData = Ext.util.JSON.decode(response.responseText);
if(JSonData.success)
dataStore.load();
else
Ext.Msg.alert(‘Status’, JSonData.failure);
},
failure: function(response, options) {
Ext.Msg.alert(‘Status’, ‘An error ocurred while trying to delete this customer.’);
}
});
}
}
);
}
});
var myGrid1 = new Ext.grid.GridPanel({
id: ‘customerslist’,
store: dataStore,
columns: [
{header: «First Name», width: 100, dataIndex: «firstname», sortable: true},
{header: «Last Name», width: 100, dataIndex: «lastname», sortable: true},
{header: «Age», width: 100, dataIndex: «age», sortable: true},
{header: «Phone», width: 100, dataIndex: «phone», sortable: true}
],
sm: new Ext.grid.RowSelectionModel({
singleSelect: true,
listeners: {
rowselect: function(smObj, rowIndex, record){
selRecordStore = record;
}
}
}),
tbar: [
btnAdd,
btnEdit,
btnDelete
],
autoLoad: false,
stripeRows: true,
height: 200,
width: 500
});
dataStore.load();
myGrid1.render(‘grid2’);
});
Так, теперь отредактируем форму:

MyPeopleForm = Ext.extend(Ext.FormPanel, {
initComponent: function(){
Ext.apply(this, {
border:false,
labelWidth: 80,
defaults: {
xtype:’textfield’,
width: 150
},
items:[
{xtype:’numberfield’,fieldLabel:’Id’,name:’id’},
{fieldLabel:’First Name’,name:’firstname’},
{fieldLabel:’Last Name’,name:’lastname’},
{xtype:’numberfield’,fieldLabel:’Age’,name:’age’},
{fieldLabel:’Phone’,name:’phone’}
]
});
MyPeopleForm.superclass.initComponent.call(this, arguments);
},
setId: function(idPerson) {
this.load(
{
method: ‘POST’,
url: ‘/cgi-bin/customerslist’,
params: {‘idperson’: idPerson}
}
);
}
});
MyPeopleWindow = Ext.extend(Ext.Window, {
constructor: function(idPerson){
MyPeopleWindow.superclass.constructor.call(this, this.config);
// if idPerson is not null, then edit record
// otherwise it’s a new record
if(idPerson != null)
this.form.setId(idPerson);
},
afterPost: function(){
this.fireEvent(‘afterPost’, this);
},
initComponent: function(){
Ext.apply(this, {
title: ‘Loading data into a form’,
bodyStyle: ‘padding:10px;background-color:#fff;’,
width:300,
height:270,
closeAction: ‘close’,
items: [ this.form = new MyPeopleForm() ],
buttons: [
{
text:’Save’,
scope: this,
handler: function(){
this.form.getForm().submit({
scope: this,
url: ‘/cgi-bin/customerslist’,
method: ‘POST’,
// here I add the param save_person
// to let the cgi program decide
// a course of action (save person data in this case).
params: {‘save_person’:’true’},
success: function(form, action){
// on success I just close the form
this.afterPost();
this.close();
},
failure: function(form, action){
Ext.Msg.alert(«Error»,»There was an error processing your request\n» + action.result.message);
}
});
}
},
{
text:’Cancel’,
handler: function(){this.close();},
// important!, without «scope: this»
// calling this.close() will try to close the Button!,
// and we need to close the Window, NOT the button.
scope: this
}
]
});
MyPeopleWindow.superclass.initComponent.call(this, arguments);
}
});


Все, интерфейс готов. Перейдем к следующему шагу и создадим новый файл customerslist.pp, содержащий код CGI приложения:
program cgiproject1;
{$mode objfpc}{$H+}
uses
Classes,SysUtils,
httpDefs,custcgi, // needed for creating CGI applications
fpjson, // needed for dealing with JSon data
Db, SqlDb, ibconnection; // needed for connecting to Firebird/Interbase;
Type
TCGIApp = Class(TCustomCGIApplication)
Private
FConn: TSqlConnection;
FQuery: TSqlQuery;
FTransaction: TSqlTransaction;
procedure ConnectToDataBase;
function GetCustomersList: string;
function GetCustomer(AIdPerson: string): string;
procedure FillJSONObject(AJson: TJsonObject);
function SavePerson(ARequest: TRequest): string;
function DeletePerson(ARequest: TRequest): string;
Public
Procedure HandleRequest(ARequest : Trequest; AResponse : TResponse); override;
end;
procedure TCGIApp.ConnectToDataBase;
begin
FConn := TIBConnection.Create(nil);
FQuery := TSqlQuery.Create(nil);
FTransaction := TSqlTransaction.Create(nil);
with FConn do
begin
DatabaseName := ‘TARJETA’;
UserName := ‘SYSDBA’;
Password := ‘masterkey’;
HostName := ‘192.168.1.254’;
Connected := True;
Transaction := FTransaction;
FQuery.Database := FConn;
end;
end;
procedure TCGIApp.FillJSONObject(AJson: TJsonObject);
begin
AJson.Add(‘id’, TJsonIntegerNumber.Create(FQuery.FieldByName(‘IdCliente’).AsInteger));
AJson.Add(‘firstname’, TJsonString.Create(FQuery.FieldByName(‘Apellido’).AsString));
AJson.Add(‘lastname’, TJsonString.Create(FQuery.FieldByName(‘Nombres’).AsString));
AJson.Add(‘age’, TJSONIntegerNumber.Create(FQuery.FieldByName(‘IdCliente’).AsInteger));
AJson.Add(‘phone’, TJsonString.Create(FQuery.FieldByName(‘TelFijo’).AsString));
end;
function TCGIApp.GetCustomersList: string;
var
lPerson: TJSONObject;
lJson: TJSONObject;
lJsonArray: TJSONArray;
begin
(* Query the database *)
FQuery.Close;
FQuery.Sql.Text := ‘select * from clientes’;
FQuery.Open;
FQuery.First;
lJsonArray := TJSONArray.Create;
lJson := TJSONObject.Create;
try
while not FQuery.Eof do
begin
lPerson := TJSONObject.Create;
fillJsonObject(lPerson);
FQuery.Next;
(* Fill the array *)
lJsonArray.Add(lPerson);
end;
(* Add the array to rows property *)
lJson.Add(‘rows’, lJsonArray);
Result := lJson.AsJSON;
finally
lJson.Free;
end;
end;
function TCGIApp.GetCustomer(AIdPerson: string): string;
var
lPerson: TJSONObject;
lJson: TJSONObject;
begin
(* Query the database *)
FQuery.Close;
FQuery.Sql.Text := ‘select * from clientes where IdCliente=’ + AIdPerson;
FQuery.Open;
FQuery.First;
lJson := TJSONObject.Create;
try
lPerson := TJSONObject.Create;
fillJsonObject(lPerson);
(* Add the array to rows property *)
lJson.Add(‘success’, ‘true’);
lJson.Add(‘data’, lPerson);
Result := lJson.AsJSON;
finally
lJson.Free;
end;
end;
function TCGIApp.SavePerson(ARequest: TRequest): string;
var
lId: string;
lFirstName: string;
lLastName: string;
lPhone: string;
lSql: string;
begin
lId := ARequest.ContentFields.Values[‘id’];
lFirstName := ARequest.ContentFields.Values[‘firstname’];
lLastName := ARequest.ContentFields.Values[‘lastname’];
lPhone := ARequest.ContentFields.Values[‘phone’];
if lId » then
lSql := ‘update clientes set ‘ +
‘nombres = »’ + lLastName + »’, ‘ +
‘apellido = »’ + lFirstName + »’, ‘ +
‘telfijo = »’ + lPhone + »’ where idcliente=’ + lId
else
begin
lSql := ‘insert into clientes(IdCliente, Nombres, Apellido, TelFijo) ‘ +
‘values(Gen_Id(SeqClientes, 1),»’ + lFirstName + »’, »’ + lLastName + »’, »’ + lPhone + »’)’;
end;
try
FQuery.Sql.Text := lSql;
FConn.Transaction.StartTransaction;
FQuery.ExecSql;
FConn.Transaction.Commit;
Result := ‘{»success»: »true»}’;
except
on E: Exception do
Result := ‘{»message»: «‘ + E.message + ‘»}’;
end;
end;
function TCGIApp.DeletePerson(ARequest: TRequest): string;
var
lId: string;
begin
lId := ARequest.ContentFields.Values[‘delete_person’];
try
FQuery.Sql.Text := ‘delete from clientes where idcliente=’ + lId;
FConn.Transaction.StartTransaction;
FQuery.ExecSql;
FConn.Transaction.Commit;
Result := ‘{»success»: »true»}’;
except
on E: Exception do
Result := ‘{»failure»: »Error deleting person.»}’;
end;
end;
Procedure TCGIApp.HandleRequest(ARequest : TRequest; AResponse : TResponse);
var
lIdPerson: string;
begin
if ARequest.ContentFields.Values[‘delete_person’] » then
begin
AResponse.Content := DeletePerson(ARequest);
end
else
if ARequest.ContentFields.Values[‘save_person’] » then
begin
AResponse.Content := SavePerson(ARequest);
end
else
begin
lIdPerson := ARequest.ContentFields.Values[‘idperson’];
if lIdPerson » then
AResponse.Content := GetCustomer(lIdPerson)
else
AResponse.Content := GetCustomersList;
end;
end;
begin
With TCGIApp.Create(Nil) do
try
Initialize;
ConnectToDatabase;
Run;
finally
Free;
end;
end.
Скомпилируйте этот файл. Для удобства компиляции, я использую простой bash скрипт. Он выполняет компилирование, а затем копирует результат в директорию /var/www/cgi-bin. Мой Apache 2 сконфигурирован именно на эту директорию. Именно в ней хранятся все мои CGI приложения.

На всякий случай привожу код своего скрипта:

#!/bin/bash
fpc -XX -Xs -b -v ./customerslist.pp
cp ./customerslist /var/www/cgi-bin

На этом на сегодня все. В этой части заметки я показал Вам, как создать HTML страницу содержащую таблицу, а также панель инструментов с кнопками для управления данными.

Понравилась статья? Поделиться с друзьями: