Home
Archives
About us...
Advertising
Contacts
Site Map
 

ruby in steel

 

BLOGGING WITH DELPHI #2 (ii)

...continued from Part 2 (i) and continued in Part 3
by Bob Swart

 

Selecting Categories

Note that the Edit, Update, Cancel and Delete options should only be available for the owner(s) of the weblogs, and not to the average visitor. This will be one of the topics and additional features added next time (which will also apply to ASP.NET development in general).

Right now, we’ve used them to fill the EcoSpace with a few Categories. But now we should focus on the average visitor, who wants to use these Categories to select associated Posts.

We need to make some changes to the DataGrid now. I still want the Name to be shown, but it should be a clickable Name, resulting in a selection of that particular Category, so we can display the associated Posts (and their Comments).

Go to the HTML Designer again, select the DataGrid, and start the Property Builder dialog again. Go to the Columns page, and add a HyperLink Column. Set its Header text to Categories, it’s Text field to Name, its URL field to ExternalId, and it’s URL format string to

Blogs.aspx?RootId={0}

Note that I’m using Blogs.aspx here, the same name as the page itself (so if you’ve renamed it to something else, you have to use that URL instead). The RootId is a hardcoded name that will be used in the Page_Load code of the ECO ASP.NET Web Page to pre-initialise the “current” object for the rhRoot ReferenceHandle to the EcoSpace.

This new Column will be the only one that regular visitors will be able to see. In order to secure our work for next time, we should not delete the first Categories column, or the Edit, Update, Cancel and Delete Columns, but simply select them in the DataGrid Properties dialog, and uncheck their Visible property checkbox.

When you close the DataGrid Properties dialog again, the DataGrid will show only one column with clickable Category Names.

To complete the transition, set the Visible property of the btnNewCategory to False as well. It will still be shown at design-time, but we won’t see it again at run-time, which is good.

If you compile and run the Weblog ECO ASP.NET application at this time, you will only see the DataGrid with the categories. You can click on one of the category names, say the first one, which will lead to the following slightly surprising result:

In the URL field, you’ll see that I’ve clicked on the first category object (with the “.NET Framework” name), which has RootId equal to 2:1. The link itself is shown in the DataGrid as well (as visited hyperlink), since the first category that I clicked on is now the last one.

If I click on another category, then the same thing happens: the current selected category will be the last one in the list. I’m sure there is an explanation for this, but I’d like to keep the list of categories sorted.

As you perhaps noticed in the previous screenshots, I did my best to enter the categories sorted by name. But in order to keep them sorted by name, I need to enforce this. The best place is to use the Expression property of the ehCategories ExpressionHandle component, since that’s the input for the DataSource property of the DataGrid.

Using the OCL expression editor, we can add an ->orderby(«<Any>») part to the Category.allInstances expression. However, the «<Any>» will obviously lead to an error message by the OCL parser, which we have to replace by an actual expression. To sort the instances by name, the solution is simple: replace «<Any>» by Name, which turns the Expression property into the following final value:

Category.allInstances->orderby(Name)

If we compile and run the application again, we can now click on the category names in the DataGrid, and while the newly clicked category will be the current category, the order in which they are listed in the DataGrid will not change.

Category and Posts

Time to add the Posts that belong to the selected Category. For this, we need to add a new ExpressionHandle, call it ehPosts, and set the AddExternalId property to True.

The RootHandle of ehPosts must be connected to the rhRoot ReferenceHandle. By default rhRoot is pointing to the entire EcoSpace. However, as soon as we click on one of the items in the Categories DataGrid, we navigate to our same Blogs.aspx page, passing a RootId in the URL field. This RootId field is picked up in the Page_Load code of the ECO web form, and used to point the rhRoot ReferenceHandle to the selected object.

The only thing we need to do is tell the rhRoot that it’s pointing to an EcoSpace object of type Category, which is done in the StaticValueTypeName property of rhRoot. This property needs to be set to Category (manually, since the drop-down combobox for the StaticValueTypeName property doesn’t show the available types yet).

As a result of all this, we can build an Expression for the ehPosts ExpressionHandle that will show all Posts related to the current selected Category.

Note that I’m already making sure the Posts are sorted by their date (the newest on top).

The result of this Expression can be displayed in a DataGrid again, so place another one on the ECO web form. I’ve placed the new DataGrid right next to the first one, with a space in between them.

The DataSource property of the second DataGrid can be connected to ehPosts, which will result in five columns being shown: ExternalId, Author, Title, Posted and Contents.

We can set use the Auto Format dialog to set the scheme of the new DataGrid to the same schema (or a different one) as the one used in the first DataGrid.

Then, start the Property Builder dialog for the second DataGrid. In the first page, specify that ExternalId is the Data key field (as we also done with the first DataGrid).

In the Columns page, uncheck the option to create columns automatically at runtime, and add only the Author and Posted columns. The Author field is optional – if you only have one author who uses the weblog application, you can leave it behind of course. The Posted column is important. Set the Date formatting expression to {0:d} if you only want to display the date of the Posted field in the DataGrid, otherwise you get the date with the time as well. Since I don’t expect to be making several weblog posts per day anyway, the date value is enough for my needs. But feel free to keep it in the original way.

And what about the Title and Contents, you may ask? Well, the title will be added as a HyperLink Column, and the Contents will not be shown here, but in the Blog.aspx detail page (that we’re about to make).

For the Title field, add a HyperLink Column that you can position before the Posted Column, set the Header Text to Title, the Text field to Text, the URL field to ExternalId, and the URL format string to the following:

Blog.aspx?RootId={0}

Note that I’m now navigating to Blog.aspx (for one individual blog) instead of Blogs.aspx (for the categories and blog titles).

Bootstrapping - again

And now, to support our bootstrapping process, we need to add a Button to add a new blog Post object to the selected category in the EcoSpace. Place a Button on the web form, set its (ID) to NewPost and its Title to “New Post”, and implement its Click event handler as follows:

procedure TWebForm1.btnNewPost_Click(sender: System.Object; e: System.EventArgs);
var
  NewPost: Post;
begin
  NewPost := Post.Create(EcoSpace);
  NewPost.Author := 'Bob Swart';
  NewPost.Title := 'Title';
  NewPost.Posted := DateTime.Now;
  NewPost.Categories.Add(rhRoot.Element.AsObject as Category);
  UpdateDatabase;
  DataBind;
end;

This code will add a new Post to the EcoSpace, set its Author, Title and Posted attributes, and add the current selected Category to the list of Categories.

If we compile and run the application, the two DataGrids are not displayed next to each other. In order to enforce that, we have to add a HTML table with two horizontal cells: one for the Categories DataGrid and New Category button, and the other for the Posts DataGrid and the New Post button.

With Table | Insert Table, we can insert a HTML table. Set the Rows to 1, Columns to 2, and the Width to 100% instead of 300 pixels. Finally, set the Border size to 0, so it won’t shown at run-time (but it will display helpful border lines at design-time). Drag the Categories DataGrid and New Categories Button in the left Table Cell, and the Posts DataGrid and New Post Button into the right Table Cell. Finally, set the valign property of both Table Cells to top.

We can also add Edit, Update, Cancel and Delete Columns to the second DataGrid, allowing us to modify the contents of new posts. However, since this will edit everything except for the actual Contents attribute, I would rather add the edit capabilities to the new page: Blog.aspx, which will display (and allow us to edit) just one weblog Post object.

The ability to Delete Posts is welcome, so we can use the Property Builder dialog to add a Delete Column. Don’t forget to connect the DeleteCommand event of the second DataGrid to the DataGrid_DeleteCommand predefined handler. Note that both DataGrids now share the same event handler.

Save, compile and run the application, and test adding new Posts to the selected category. You can also verify that a click on another Category will refresh the list of Posts, only showing those Posts that belong to that particular Category.

Note that the Posts are sorted by date – the most recent on top. The only thing that is not obvious from the last screenshot is the current selected category. This can be clarified by placing an ASP.NET Label control just above the second DataGrid. Set its (ID) property to lbCategory, and set the Font sub-properties to something that is big and easy to read. Clear the text property, as we’ll add a value in code.

Now, double-click on the Web Form itself, which will bring us to the Page_Load event handler, where the code is present to look for the RootId query field, pointing the rhRoot ReferenceHandle to the selected Category object. If the RootId field is found, then we should also assign the Name of the currently selected Category to the lbCategory Label, which takes just one additional line of code (marked with // BS ) as follows:

procedure TWebForm1.Page_Load(sender: System.Object; e: System.EventArgs);
var
  Id: string;
begin
  EcoSpace.Active := True;
  Id := Request.Params['RootId'];
  if Assigned(Id) and (Id <> '') then
  begin
    rhRoot.SetElement(ObjectForId(Id));
    lbCategory.Text := (rhRoot.Element.AsObject as Category).Name; // BS
  end;
  if not IsPostBack then
    DataBind;
  // TODO: Put user code to initialize the page here
end;

With this last addition, we can view the Blogs page in action as follows:

New ECO ASP.NET Blog Page

We now need to create the new ECO Web Form, called Blog.aspx, and make sure it will show the current Post object. Do File | New – Other, and go to the New ASP.NET Files subcategory of the Delphi for .NET Projects category, and double-click on the ECO ASP.NET Page icon.

This will produce a new ECO ASP.NET web form, that we should save as Blog.aspx (the name we used in the Title HyperLink Column).

This new ECO web form also has an rhRoot component in the non-visual components area of the HTML Designer. This time, we need to tell it that the EcoSpaceType property value is WeblogEcoSpace.TWeblogEcoSpace (just open up the drop-down combobox and select the only value), and that the StaticValueTypeName is Post.

Before we can continue, we need to make sure that the second WebForm can access the objects and types from the CoreClassesUnit. Go to the top of the Blog.pas unit, and add the unit CoreClassesUnit to the uses clause of the interface section.

Showing Post Contents

We can now add controls to the Blog.aspx page to display the attributes (Author, Title, Posted and Contents) from the current selected Post. However, this page can be seen in two different ways: either read-only, by a weblog visitor, or in edit mode, by the actual author of the weblog.

As I’ve already hinted earlier, next month I’ll cover authentication and authorization, so for now let’s focus on the more complex of the two cases: the edit-mode, where the information should be presented in a read/write format. Not everything, by the way, since we can assume that the Author and Posted attributes will not have to change, so only the Title and actual Contents need to be edited.

In order to support a nice layout, let’s start by inserting a HTML Table on the Blog web form, with 2 columns and 4 rows, a width of 100 percent, and border size set to 0. Feel free to add a nice background colour or image if you wish.

In the first column of the last row, I’ve placed a HyperLink control from the Web Controls category, with the Text property set to Back and the NavigateUrl property set to Blogs.aspx, the page with the Categories and Posts per Category.

In the second column of the first row of the HTML table, I’ve placed a Label called lbPosted. In the second column of the second row I’ve placed a TextBox called tbTitle. In the third row I’ve placed a TextBox called tbContents, this time with the TextMode set to MultiLine, the Rows property set to 8 (for 8 Lines) and the Width property set to 100%. Finally, in the last row, I’ve placed another Label again, called lbAuthor.

I’ve cleared the Text property of the two Label controls, since we can assign them in the Page_Load event of the web form, as follows (again, the only two new lines are the once with the // BS comment, plus the begin-end pair around them):

procedure TWebForm1.Page_Load(sender: System.Object; e: System.EventArgs);
var
  Id: string;
begin
  EcoSpace.Active := True;
  Id := Request.Params['RootId'];
  if Assigned(Id) and (Id <> '') then
  begin
    rhRoot.SetElement(ObjectForId(Id));
    lbPosted.Text := (rhRoot.Element.AsObject as Post).Posted.ToString; // BS
    lbAuthor.Text := (rhRoot.Element.AsObject as Post).Author;          // BS
  end;
  if not IsPostBack then
    DataBind;
  // TODO: Put user code to initialize the page here
end;

For the two TextBox controls, we can use a similar technique, although we can also use the DataBinding functionality (which means we don’t have to write any source code).

To demonstrate the later, select the tbTitle TextBox, and in the Object Inspector double-click on the (DataBindings) property to start the tbTitle DataBindings wizard. We have to bind the Text property of tbTitle to the Title field of the rhRoot.[0] item.

In a similar way, we can bind the Text property of the tbContents TextBox control to the ehPost[0].Contents field.

Save Changes

All we need to add now, is a final Button to apply the changes in the tbTitle and tbContents TextBox controls back to the current Post object in the EcoSpace, and update the database again.

For this, place a new Button on the web form, for example in the last column of the last row, set the (ID) property to btnSaveChanges, and the Title property to “Save Changes”. The implementation of the Click event should now be no problem: we have to cast the rhRoot to the current Post again, set the Title and Content properties, and call UpdateDatabase to ensure that the database is updated with the changes. That’s all.

procedure TWebForm1.btnSaveChanges_Click(sender: System.Object;
  e: System.EventArgs);
begin
  with (rhRoot.Element.AsObject as Post) do
  begin
    Title := tbTitle.Text;
    Contents := tbContents.Text;
  end;
  UpdateDatabase;
  DataBind
end;

We can now save, compile and run the ECO ASP.NET weblog application. Go to the Enterprise Core Objects category, and select the Post of today, so I can edit the Title and Contents.

Clicking on Save Changes will post the modifications to the EcoSpace. And using the Back button we get back to the main page where we can select the Categories and individual Posts again.

Note that we still haven’t written more than a few dozen lines of code! Still, full source code is available for download from the Bitwise Magazine website (delphiblog2.zip).

Next Time...

Next month, we’ll add some management capabilities to the application, adding authentication and authorization, making sure that the weblog author can add and edit Categories and Posts, and delete Comments (if needed), while weblog visitors can only read Categories, Posts and Comments by others, or add their own Comments.

All this and more next time, so stay tuned...

Copyright © 2005 Bob Swart


Bob Swart (aka Dr.Bob - www.drbob42.com) is an author, trainer, developer, consultant and webmaster for Bob Swart Training & Consultancy (eBob42) in The Netherlands, who has spoken at Delphi and Borland Developer Conferences since 1993. Bob has written chapters for seven books, as well as the Borland Delphi 8 for .NET Essentials and Delphi 8. ASP.NET Essentials courseware manuals licensed by Borland worldwide, and is selling his updated Delphi 2005 courseware manuals online at http://www.drbob42.com/training. Bob received the Spirit of Delphi award at BorCon in 1999, together with Marco Cantù.

June 2005

 

 


Home | Archives | Contacts

Copyright © 2006 Dark Neon Ltd. :: not to be reproduced without permission