Delphi Programming Guide
Delphi Programmer 

Menu  Table of contents

Part I - Foundations
  Chapter 1 – Delphi 7 and Its IDE
  Chapter 2 – The Delphi Programming Language
  Chapter 3 – The Run-Time Library
  Chapter 4 – Core Library classes
  Chapter 5 – Visual Controls
  Chapter 6 – Building the User Interface
  Chapter 7 – Working with Forms
Part II - Delphi Object-Oriented Architectures
  Chapter 8 – The Architecture of Delphi Applications
  Chapter 9 – Writing Delphi Components
  Chapter 10 – Libraries and Packages
  Chapter 11 – Modeling and OOP Programming (with ModelMaker)
  Chapter 12 – From COM to COM+
Part III - Delphi Database-Oriented Architectures
  Chapter 13 – Delphi's Database Architecture
  Chapter 14 – Client/Server with dbExpress
  Chapter 15 – Working with ADO
  Chapter 16 – Multitier DataSnap Applications
  Chapter 17 – Writing Database Components
  Chapter 18 – Reporting with Rave
Part IV - Delphi, the Internet, and a .NET Preview
  Chapter 19 – Internet Programming: Sockets and Indy
  Chapter 20 – Web Programming with WebBroker and WebSnap
  Chapter 21 – Web Programming with IntraWeb
  Chapter 22 – Using XML Technologies
  Chapter 23 – Web Services and SOAP
  Chapter 24 – The Microsoft .NET Architecture from the Delphi Perspective
  Chapter 25 – Delphi for .NET Preview: The Language and the RTL
       
  Appendix A – Extra Delphi Tools by the Author
  Appendix B – Extra Delphi Tools from Other Sources
  Appendix C – Free Companion Books on Delphi
       
  Index    
  List of Figures    
  List of tables    
  List of Listings    
  List of Sidebars  

 
Previous Section Next Section

Web Database Applications

As in Delphi's libraries, a significant portion of IntraWeb's available controls relates to the development of database applications. The IntraWeb Application Wizard has a version that allows you to create an application with a data module—a good starting point for the development of a database application. In such a case, the application's predefined code creates an instance of the data module for each session, saving it in the session's data.

Here is the predefined TUserSession class (and its constructor) for an IntraWeb application with a data module:

type
  TUserSession = class(TComponent)
  public
    DataModule1: TDataModule1;
    constructor Create(AOwner: TComponent); override;
  end;
   
constructor TUserSession.Create(AOwner: TComponent);
begin
  inherited;
  Datamodule1 := TDatamodule1.Create(AOwner);
end;

The unit of the data module doesn't have a global variable for it; if it did, all the data would be shared among all sessions, with severe risks of trouble in case of concurrent requests in multiple threads. However, the data module already exposes a global function having the same name as the global variable Delphi would use, accessing the current session's data module:

function DataModule1: TDataModule1;
begin
  Result := TUserSession(RWebApplication.Data).Datamodule1;
end;

This means you can write code like the following:

DataModule1.SimpleDataSet1

But instead of accessing a global data module, you are using the current session's data module.

In the first sample program featuring database data, called IWScrollData, I've added to the data module a SimpleDataSet component and to the main form an IWDBGrid component with the following configuration:

object IWDBGrid1: TIWDBGrid
  Anchors = [akLeft, akTop, akRight, akBottom]
  BorderSize = 1
  CellPadding = 0
  CellSpacing = 0
  Lines = tlRows
  UseFrame = False
  DataSource = DataSource1
  FromStart = False
  Options = [dgShowTitles]
  RowAlternateColor = clSilver
  RowLimit = 10
  RowCurrentColor = clTeal
end

The most important settings are the removal of a frame hosting the control with its own scroll bars (the UseFrame property), the fact that the data is displayed form the current data set position (the FromStart property), and the number of rows to be displayed in the browser (the RowLimit property). In the user interface, I've removed vertical lines and colored alternate rows. I also had to set up a color for the current row (the RowCurrentColor property); otherwise the alternate colors won't appear to work properly, since the current row is the same color as the background rows, regardless of its position (set the RowCurrentColor property to clNone to see what I mean). These settings produce the effect you can see in Figure 21.7 or by running the IWScrollData example.

Click To expand
Figure 21.7: The data-aware grid of the IWScrollData example

The program opens the data set when the form is created, using the data set hooked to the current data source:

procedure TformMain.IWAppFormCreate(Sender: TObject);
begin
  DataSource1.DataSet.Open;
end;

The example's relevant code is in the button code, which can be used to move through the data showing the following page or returning to the previous one. Here is the code for one of the two methods (the other is omitted, because it's very similar):

procedure TformMain.btnNextClick(Sender: TObject);
var
  i: Integer;
begin
  nPos := nPos + 10;
  if nPos > DataSource1.DataSet.RecordCount - 10 then
    nPos := DataSource1.DataSet.RecordCount - 10;
  DataSource1.DataSet.First;
  for i := 0 to nPos do
    DataSource1.DataSet.Next;
end;

Linking to Details

The grid of the IWScrollData example shows a single page of a table's data; buttons let you scroll up and down the pages. An alternative grid style in IntraWeb is offered by framed grids, which can move larger amounts of data to the web browser within a screen area of a fixed size using a frame and an internal scroll bar, as a Delphi ScrollBox control does. This is demonstrated by the IWGridDemo example.

The example customizes the grid in a second powerful way: It sets the Columns collection property of the grid. This setting allows you to fine-tune the output and behavior of specific columns, for example by showing hyperlinks or handling clicks on items or title cells. In the IWGridDemo example, one of the columns (the last name) is turned into a hyperlink; the employee number is passed as a parameter to the follow-up command, as you can see in Figure 21.8.

Click To expand
Figure 21.8:  The main form of the IWGridDemo example uses a framed grid with hyperlinks to the secondary form.

Listing 21.1 shows a summary of the grid's key properties. Notice in particular the last name column, which as mentioned has a linked field (which turns the cell's text into a hyperlink) and an event handler responding to its selection. In this method, the program creates a secondary form in which a user can edit the data:

procedure TGridForm.IWDBGrid1Columns1Click(ASender: TObject;
  const AValue: String);
begin
  with TRecordForm.Create (WebApplication) do
  begin
    StartID := AValue;
    Show;
  end;
end;
Listing 21.1: Properties of the IWDBGrid in the IWGridDemo Example
Start example
object IWDBGrid1: TIWDBGrid
  Anchors = [akLeft, akTop, akRight, akBottom]
  UseFrame = True
  UseWidth = True
  Columns = <
    item
      Alignment = taLeftJustify
      BGColor = clNone
      DoSubmitValidation = True
      Font.Color = clNone
      Font.Enabled = True
      Font.Size = 10
      Font.Style = []
      Header = False
      Height = '0'
      VAlign = vaMiddle
      Visible = True
      Width = '0'
      Wrap = False
      BlobCharLimit = 0
      CompareHighlight = hcNone
      DataField = 'FIRST_NAME'
      Title.Alignment = taCenter
      Title.BGColor = clNone
      Title.DoSubmitValidation = True
      Title.Font.Color = clNone
      Title.Font.Enabled = True
      Title.Font.Size = 10
      Title.Font.Style = []
      Title.Header = False
      Title.Height = '0'
      Title.Text = 'FIRST_NAME'
      Title.VAlign = vaMiddle
      Title.Visible = True
      Title.Width = '0'
      Title.Wrap = False
    end
    item
      DataField = 'LAST_NAME'
      LinkField = 'EMP_NO'
      OnClick = IWDBGrid1Columns1Click
    end
    item
      DataField = 'HIRE_DATE'
    end
    item
      DataField = 'JOB_CODE'
    end
    item
      DataField = 'JOB_COUNTRY'
    end
    item
      DataField = 'JOB_GRADE'
    end
    item
      DataField = 'PHONE_EXT'
    end>
  DataSource = DataSource1
  Options = [dgShowTitles]
end
End example

By setting the second form's StartID property, you can locate the proper record:

procedure TRecordForm.SetStartID(const Value: string);
begin
  FStartID := Value;
  DataSource1.DataSet.Locate('EMP_NO', Value, []);
end;
Tip 

The IWDBGrid columns have also an OnTitleClick event you can handle to sort the data or perform other operations on the column.

The secondary form is hooked to the same data module as the main form. So, after the database data is updated, you can see it in the grid (but the updates are kept only in memory, because the program doesn't have an ApplyUpdates call). The secondary form uses a few edit controls and a navigator, provided by IntraWeb. You can see this form at run time in Figure 21.9.

Click To expand
Figure 21.9: The secondary form of the IWGridDemo example allows a user to edit the data and navigate through records.

Moving Data to the Client Side

Regardless of how you use it, the IWDBGrid component produces HTML with the database data embedded in the cells, but it cannot work on the data on the client side. A different component (or a set of IntraWeb components) allows you to follow a different model. The data is sent to the browser in a custom format, and the JavaScript code on the browser populates a grid and operates on the data, moving from record to record without asking more data to the server.

Note 

This architecture is similar to Delphi's native Internet Express architecture, which I'll cover in Chapter 22 ("Using XML Technologies").

You can use several IntraWeb components for a client-side application, but these are the most important ones:

IWClientSideDataSet  An in-memory dataset you define by setting the ColumnNames and Data properties within your program's code. In future updates, you will be able to edit client-side data, sort it, filter it, define master-detail structures, and more.

IWClientSideDataSetDBLink  A data provider you can connect to any Delphi dataset, connecting it with the DataSource property.

IWDynGrid  A dynamic grid component connected to one of the two previous components using the Data property. This component moves all the data to the browser and can operate on it on the client via JavaScript.

There are other client-side components in IntraWeb, such as IWCSLabel, IWCSNavigator, and IWDynamicChart (which works only with Internet Explorer). As an example of using this approach, I've built the IWClientGrid example. The program has little code, because there is a lot available in the components being used. Here are the core elements of its main form:

object formMain: TformMain
  SupportedBrowsers = [brIE, brNetscape6]
  OnCreate = IWAppFormCreate
  object IWDynGrid1: TIWDynGrid
    Align = alClient
    Data = IWClientSideDatasetDBLink1
  end
  object DataSource1: TDataSource
    Left = 72
    Top = 88
  end
  object IWClientSideDatasetDBLink1: TIWClientSideDatasetDBLink
    DataSource = DataSource1
  end
end

The dataset from the data module is hooked to the DataSource when the form is created. The resulting grid, shown in Figure 21.10, allows you to sort the data on any cell (using the small arrow after the column title) and filter the data displayed on one of the field's possible values. In the figure, for example, you can sort the employee data by last name and filter it by country and job grade.

Click To expand
Figure 21.10: The grid of the IWClientGrid example supports custom sorting and filtering without re-fetching the data on the web server.

This functionality is possible because the data is moved to the browser within the JavaScript code. Here is a snippet of one of the scripts embedded in the page's HTML:

<script language="Javascript1.2">
var IWDYNGRID1_TitleCaptions =
  ["EMP_NO","FIRST_NAME","LAST_NAME","PHONE_EXT",
  "DEPT_NO","JOB_CODE","JOB_GRADE","JOB_COUNTRY"];
var IWDYNGRID1_CellValues = new Array();
IWDYNGRID1_CellValues[0] = [2,'Robert','Nelson','332','600','VP',2,'USA'];
IWDYNGRID1_CellValues[1] = [4,'Bruce','Young','233','621','Eng',2,'USA'];
IWDYNGRID1_CellValues[2] = [5,'Kim','Lambert','22','130','Eng',2,'USA'];
IWDYNGRID1_CellValues[3] = [8,'Leslie','Johnson','410','180','Mktg',3,'USA'];
IWDYNGRID1_CellValues[4] = [9,'Phil','Forest','229','622','Mngr',3,'USA'];
Note 

The reason to use this JavaScript-based approach, instead of an XML-based approach featured by other similar technologies, is that only Internet Explorer has support for XML data islands. Mozilla and Netscape lack this feature and have limited XML support in general. Mimicking it in JavaScript, as Internet Explorer does, is very expensive at run time.


 
Previous Section Next Section


 


 

Delphi Sources


Copyright © 2004-2024 "Delphi Sources" by BrokenByte Software. Delphi Programming Guide
ร๐๓๏๏เ ยส๎ํ๒เ๊๒ๅ   Facebook   ั๑๛๋๊เ ํเ Twitter