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:
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.
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;
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.
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;
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
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;
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.
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.
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.