By: Nick Hodges
Abstract: This article continues our series on WebSnap and shows you how to add items to a database using WebSnap. By Nick Hodges.
Now, where were we?
It has been a while since I have submitted an installment in the WebSnap Chronicles. When I last checked in
with you, I showed how to create automatic paging for your Web pages, both with grids and by formatting data
however you want it. Remember, the trick is that paging works only with grids, and if you want to customize
the data, you need to put it into a grid with a single column. I illustrated that for you by creating a Weblog.
The Weblog was all well and good, but it was hard to make additions to it. You either wrote yourself a
little application or you used a tool to add your entries manually. But that's no way to blog. You need
something handy, something that's always at the ready, so you can pontificate as the mood strikes you.
You, my fine programming friend, need to be able to make that profound Weblog entry that will likely change
perceptions about the truth of the universe wherever you are. You need a Web app.
Fortunately, you are about to find out how you can update your Weblog from your Web site itself. You'll
be able to make entries right into the log that will show up immediately, and since you are an expert
at access rights, you'll be the
only one who even knows that it can be done.
First, however, there are some housekeeping tasks ahead of us. The first is you'll want to fix
some, ahem, problems with WebSnap. Corbin Dunn,
a QA Engineer with Borland and a dedicated newsgroup participant, has
put together a page of fixes and comments on WebSnap
that you'll want to look at. For this article, you will definitely want to apply the fixes for the
crash that happens when you shut down your app
and that irritating "cannot perform this operation on a closed dataset error".
If you have applied the first update to Delphi 6.0, then you may want to do some of the other fixes as
well. By the way, Corbin has indicated that there will be a second update 2 for Delphi 6, so more fixes to
WebSnap are on the way. In addition, Corbin is very responsive to questions and problems on the WebSnap
newsgroups (he should really get a raise or a medal or some other fine thing), so if you do have questions
and problems, feel free to post there.
Next, make sure that you've gone back to the PagedAdapter article and done the "fixes" to our application
that are at the beginning of the article. Make sure to install the new nxEndUserSessionAdapter component, in
particular. Then, if you want, you can download the
code for this article from
Code Central, and the IDE won't complain when you try to load the project. In addition, I have put up
a Web page that outlines some WebSnap resources on the Web.
Feel free to visit and take advantage of some of the good links there. In addition, if you have any
additions to the page that you think ought to be there, be sure to let me know.
Third, this article assumes that you have an existing application in the state it was left in at the
end of the PagedAdapter article, and the instructions below assume that you are adding to that application.
If not, you can download that application from CodeCentral
and start from there.
That ought to do it for catching up and squaring things away, so let's get on to the new stuff you want
to learn about.
BLOGGING THE WEBSNAP WAY
Okay, to get this thing going, we'll need to make some changes to the database. In
the last article, you used
an Interbase database called WEBLOG.GDB. It held
basic information about each entry. Now that we are going to be adding items to it, we need a
way to get unique values for the ID field. The normal way to do this is to use a generator to
guarantee a unique value, and then to access it from the database with a stored procedure.
In order to do that, you have to add a generator and a stored procedure. (Duh!) Run the
following SQL against the database to add the generator:
CREATE GENERATOR "WEBLOG_ID_GEN";
Then run this SQL to add the stored procedure. If you don't want to bother with that, the code in
CodeCentral has the database in it all ready to go. (Note that it also includes some cheesy entries
that you might want to delete.)
SET AUTODDL OFF;
SET TERM ^ ;
/* Stored procedures */
CREATE PROCEDURE "CREATEWEBLOGID"
BEGIN EXIT; END ^
ALTER PROCEDURE "CREATEWEBLOGID"
AVALUE = gen_id(WEBLOG_ID_GEN, 1);
SET TERM ; ^
SET AUTODDL ON;
YOU KNOW WHAT TO DO
Now that the database is all ready to go, you should add another page to the application. You
know what to do. (If you don't know what to do, then go back to some of my earlier articles
and review the process of adding pages to your application.) Name the page AddWebLog, give it a
TAdapterPageProducer, and save the page as wmAddWebLog.pas. Then limit its access by making the
factory call in the initialization section look like this:
// Change the AccessRights for this page.
// See the article at http://community.borland.com/article/0,1410,27777,00.html for more information about this
if WebRequestHandler <> nil then
WebRequestHandler.AddWebModuleFactory(TWebPageModuleFactory.Create(TAddWebLog, TWebPageInfo.Create([wpPublished, wpLoginRequired], '.html', '', '', '', 'CanAddWebLog'), crOnDemand, caCache));
Doing this will allow only users with "CanAddWebLog" in their AccessRights property to view the
page. While you are at it, add "CanAddWebLog" to one of your users in the WebUserList component
on your Home page. If you forget to do that, then you won't even be able to view the new page you
created, and that would be just silly, right?
Now add the following components, naming them according to the table below:
Now take the following steps:
That ought to take care of the database end of things. (Is it just me, or is WebSnap very
mouse-click intensive? Man, look at all the steps...!) Now it's off to set up the key component here,
the dsaWebLog DatasetAdapter. That's the component that will manage all the data on the Web page. But
you know that already, right? Anyway, take the following steps on the dsaWebLog component:
Now that you are sick of all that mouse clicking, it's finally time to add a little code. Go
back to the Field Editor for the dsaWebLog and select the AdaptENTRYDATETIME field. Add this code
to the OnGetDisplayText event handler:
procedure TAddWebLog.AdaptENTRYDATETIMEGetDisplayText(Sender: TObject;
Field: TField; var Value: String);
// Display the current date time. It's not the actual value that will end up
// in the database, but it gives the user some feedback that the entry is there
DateFormat := Format('%s %s', [ShortDateFormat, ShortTimeFormat]);
Value := '<B>' + FormatDateTime(DateFormat, Now) + '</B>';
This will format the text for the date/time in the web page. Next, add this to the OnGetValue event of the AdaptTITLE:
procedure TAddWebLog.AdaptTITLEGetValue(Sender: TObject; Field: TField;
var Value: Variant);
// We want these values blank when they show up, as this is a new entry.
Value := '';
And add this to the OnGetValue of the AdaptENTRYTEXT:
procedure TAddWebLog.AdaptENTRYTEXTGetValue(Sender: TObject; Field: TField;
var Value: Variant);
// We want these values blank when they show up, as this is a new entry.
Value := '';
Those last two code entries are a little strange. I found that you have to manually enter blank values to the
fields that you want to insert, as the default values are the current record in the database. I assure you that
the database is in insert mode (remember above when we set the AdapterMode to Insert?), but without the above
handlers, the controls will have the values of the last record in them. This is likely a bug and I'll report
it to Borland.
Do all that, and you should see something like this in the TAdapterPageProducer:
Now we'll put that stored procedure to work. Add the following public method to the AddWebLog webmodule:
function TAddWebLog.CreateNewWebLogID: integer;
// Execute the stored procedure and get the result of the generator
Result := spNewWebLogID.Params.ParamValues['AValue'];
While you're at it, add this code to the dsaWebLog's AfterUpdateFields event:
procedure TAddWebLog.dsaWebLogAfterUpdateFields(Sender: TObject;
ActionRequest: IActionRequest; AdapterFields: TObjectList);
if cdsWebLog.UpdateStatus = usInserted then
// Fix up the text that comes through.
// Get a unique ID value
cdsWebLogID.AsInteger := CreateNewWebLogID;
// Set the entry date/time to now
cdsWebLogENTRYDATETIME.AsDateTime := Now;
// Make sure there aren't any characters in the text that will gum up a webpage.
cdsWebLogTITLE.AsString := EscapeText(cdsWebLogTITLE.AsString);
cdsWebLogENTRYTEXT.AsString := EscapeText(cdsWebLogENTRYTEXT.AsString);
Actually, this is the key code. This is where the information is actually sent to the database.
The entry's date and time are set, and then the text for the title and the entry is cleaned up. The
EscapeText function, found in the WebSnapUtils.pas unit, replaces the <, >, & and "
characters with their HTML equivalents.
You need to make sure that the ClientDataset always reconciles itself back to the database, so
whenever there is an action, either Apply or Cancel, you need to run this code in the Web module's
AfterExecuteAction event handler. Do so as follows:
Action: TObject; Params: TStrings);
// Clientdatasets need to be applied all the way back to the server, or whatever is on the
// other end of the DatasourceProvider. If there is a modification waiting, apply it. If not,
// cancel the transaction
if cdsWebLog.UpdateStatus <> usUnmodified then
on E: Exception do
// Add any exceptions to the Adapter's Error property, so they will show up in a
WILL PROPERTIES NEVER CEASE?
Okay, more property settings. Once the entry is complete and you press the Apply button, you'll likely
want to see your handiwork right away. The way to do that -- and the way to make any command go to another
page -- is to set the PageName property of the Command. Go to the Web Surface Designer of the TAdapterPageProducer
and change the PageName property of both commands to WebLogPage. This will cause the application to go to
the WebLog when either button is pushed.
It is easy to get confused between Actions and Commands. Actions are part of a TAdapter,
and they define specific actions of the TAdapter. They can be called manually in your server-side script.
Commands are the HTML representation of Actions in a TAdapterPageProducer, and are normally represented by
buttons or links on an HTML page. I do find that I sometimes bounce between an Action and the Command
representing that action looking for a property, often guessing wrong and going to the Action when I should
have gone to the Command, and vice-versa. After a while you'll start to get the hang of it. Generally, if
it has to do with the appearance on the Web page, it is a Command Property, and if it has to do with handling
a value or the code behind an action, it is a property or event of the Action.
In keeping with this, you will probably want a button on your WebLog page that will allow you, and only
you, to move to the AddWebLog page. To do that, take the following steps:
FINALLY, IT OUGHT TO WORK
Man, that is a lot of work. And the really nutty thing is, if you miss one thing, the whole app
probably won't work right. I hope I didn't miss any steps in describing it to you! Anyway,
if you compile the application and run it, you should be able to log in as your "special" user and see
the AddWebLog page.
Add a new entry title and text, then hit the Apply button. You should see your new entry on your WebLog
page. If you are on the page and decide you don't want to make the entry, hit the Cancel button, and all is forgotten.
There you go! From anywhere in the world, you can add an entry to your Weblog...right from your own Web site.
Gotta love that.
Try Delphi XE4 free for 30 days
New Instant Trial!
Webinars on demand!
More social media choices:
Delphi on Google+
@RADTools on Twitter
Server Response from: ETNASC01