Skip to content

Dynamic Creation of IntraWeb Components

For the past couple of days I’ve been working on an experimental IntraWeb (a.k.a., "VCL for the Web") project. Since I typically generate user interfaces dynamically, I wanted to see how that worked with IntraWeb. On the surface, it’s fairly similar to the regular VCL, but there are some important differences.

Rule number one is that all components you create must have the Name property set. The regular VCL doesn’t require this for components created in code, but IntraWeb uses the Component.Name as part of the HTML id, and if the id isn’t set, the JavaScript generated by IntraWeb won’t work. So always set the Name.

Another thing to note is that the default property values don’t always make sense. If a component looks different when you dynamically generated at runtime versus when you drop it on an IntraWeb form in the designer, take a close look at the text DFM. You’ll probably find non-default property values set by the designer. If you replicate this in your code, you should end up with a component looks the same at runtime.

With all that said, here’s some simple code to add tabs at runtime to an existing tab control:

uses   Graphics, IWContainerBorderOptions;

procedure TfrmUIPageGroup.ClearPageControls;
var
  iPage: integer;
begin
  for iPage := Pred(TabControl.Pages.Count) downto 0 do begin
    TObject(TabControl.Pages[iPage]).Free;
  end;
end;

procedure TMyIntraWebForm.AddSomeTabs;
var
  iPage, iTabTop, iTabHeight, iTabWidth: integer;
  NewTab: TIWTabPage;
begin
  // need to have a design-time page to copy sizing properties from
  Assert(TabControl.Pages.Count > 0);
  iTabTop := TIWTabPage(TabControl.Pages[0]).Top;
  iTabHeight := TIWTabPage(TabControl.Pages[0]).Height;
  iTabWidth := TIWTabPage(TabControl.Pages[0]).Width;
  ClearPageControls;
  for iPage := 0 to 2 do begin
    NewTab := TIWTabPage.Create(TabControl);
    NewTab.BorderOptions.NumericWidth := 0;
    NewTab.BorderOptions.BorderWidth := cbwNumeric;
    NewTab.BorderOptions.Style := cbsNone;
    NewTab.BorderOptions.Color := clNone;
    NewTab.Color := clWebWHITE;
    NewTab.Top := iTabTop;
    NewTab.Width := iTabWidth;
    NewTab.Height := iTabHeight;
    // WordPress changes the single quote to a typographic quote here, so cutting
    // and pasting the next two lines won't work. Sorry; I haven't figured out how
    // to stop that
    NewTab.Name := 'DynamicPage' + IntToStr(iPage);
    NewTab.Title :=  'Page ' + IntToStr(iPage);
    NewTab.Parent := TabControl;
    // TabOrder determines the order of tabs (really!) in this control
    // It must be set *after* Parent
    NewTab.TabOrder := iPage;
  end;
end;

Alignment may not work as expected, either. If I build on this example by creating a control, parenting it to the tab sheet, and setting the Align property to alClient, that control’s size or position doesn’t actually change.

Finally, there is the issue of layout managers. If you use TIWTemplateProcessorHTML or TIWLayoutMgrHTML, there will not be a placeholder in your template for your dynamically generated component. There is probably a way around this, but I have not fully investigated the issue yet. One possible solution would be to do the dynamic component generation inside of a custom IntraWeb control.

{ 4 } Comments

  1. Olaf Monien | March 6, 2008 at 6:51 am | Permalink

    The issue with dynamic controls and templates is a bit like the egg-chicken issue. If you create a Template, then you need to know about controls that do not exist yet.
    If you know the names of the controls that may be created dynamically later on, then you can place the corresponding variables in the template upfront. IW will just ignore unknown variables.

  2. Craig Stuntz | March 6, 2008 at 8:56 am | Permalink

    Olaf, what would be ideal is a way to dynamically alter the template. You can do this in ASP.NET templates by putting in inline code, for example.

    I’m thinking that a more "IntraWeb-ish" approach to this would be to have an event on the layout managers which would be called for each placeholder in the template. That event would allow alteration of the placeholder before the template itself is processed. I could, for example, turn one placeholder into 10 placeholders with markup in between. After the event is called for each placeholder, IntraWeb would process the template as usual.

  3. Anders Melander | March 8, 2008 at 8:45 am | Permalink

    Theoretically WordPress shouldn’t alter anything inside a PRE tag and most of the time it doesn’t, but if you switch back and forth between the code view and the editor, or if you edit the post after it has been published, the editor will mess with the quotes. This is documented in the WordPress Codex:

    http://codex.wordpress.org/Writing_Code_in_Your_Posts#Quotes_in_Codes

    One solution is to install a plugin that handles the special (non)formatting required by source code snippets. Here’s a few (I haven’t tried any of them yet)

    http://priyadi.net/archives/2005/09/27/wordpress-plugin-code-autoescape/
    http://www.semiologic.com/software/wp-fixes/unfancy-quote/

    Finally Lorelle has something to say on the topic (although I couldn’t spot any real solutions in her article):

    http://www.blogherald.com/2007/07/16/writing-and-publishing-code-in-your-wordpress-blog-posts/

  4. Jason Southwell | March 20, 2008 at 1:52 pm | Permalink

    FYI, the Arcana template processor (recently open sourced in the Elite Suite) does support altering the template before it’s processed. You must do so as a string replacement, but it does work.

{ 1 } Trackback

  1. [...] recently wrote about limitations in creating IntraWeb components dynamically when using the template processor component. It looks like the Arcana template processor, recently [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

Bad Behavior has blocked 1846 access attempts in the last 7 days.

Close