Robert/Jesse,

Thanks for the great responses.  To elaborate:

As I mentioned we have a standard order form with address, phone, etc.. 
Then beneath it will be a list of text fields that are unique to each 
company.  Each field has a label, a text field, and a default value.  So, 
we have several db objects.

Company (contains name, billing codes, etc.)
CustomField (contains label, field name, and default value)

Company has 0...n CustomFields.

When the form is displayed, the static form components are laid out in 
rows & columns, all nice & neat like you would expect.  The custom text 
fields are then (for now) simply listed is a single column all the way 
down the page (we'll worry about multiple columns later).  It's a little 
unwieldy looking, but the goal is to get the data in, not win a Best of 
the Web award.  That comes later.  ;-))

The Custom Fields in the db are assigned to each company in a Company 
Admin page.  It's what you might expect--a growable table of 
label/name/value columns.  You can add/delete/edit the list for each 
Company.  Yes, the custom fields can be changed at runtime since a company 
may change their requirements at any time.  In reality, these custom 
fields will change, at most, once per year.

The number of custom fields is determined simply by the association 
between the company and the CustomField objects. 
Company.getCustomFields().size()  So yes, this is  very runtime kind of 
thing.

There is a Company List page, listing all the companies.  You select a 
company & go to the Custom Field Admin page where you build the list for 
the company you selected.  You hit Save and can then go edit a different 
company.  (I know this seems a bit obvious, but I'll lay it all out for 
you anyway).

We very much want to avoid having a separate Company Page for each 
company.  That could result in hundreds of pages to maintain, rather than 
just 2 or 3 db tables through 1 or 2 admin screens.  Also, we would have 
to re-generate all those pages every time we upgrade Tapestry or there's a 
change to HTML or Javascript or whatever else.  If one of those 
technologies changes, with our desired approach, then only one template 
needs to be updated. 

The key here is configurability/flexibility.  Also, what if, several years 
down the road, our UI technology changes?  We want to separate the data 
from the framework so our domain model is resuable. Furthemore, we want 
the data to be available to other dev groups who may not be using 
Java/Tapestry, but will need access to the data.

I hope that's a thorough explanation.  Does it change your 
recommendations?

My continued thanks for your assistance,
  - Mike




Robert Zeigler <[EMAIL PROTECTED]> 
01/26/2006 06:12 PM
Please respond to
"Tapestry users" <tapestry-user@jakarta.apache.org>


To
Tapestry users <tapestry-user@jakarta.apache.org>
cc

Subject
Re: instantiating components directly






Jesse's idea seems reasonable. I was about to spout off some ideas, but
then realized that I need to understand your situation better first. :)
In particular, can you explain in more detail how the components are
configured from a db or xml file? More explicitly, is the number and
type of components determined by the db or xml file? Or is it just the
parameters for the n components which are determined by the db/xml file?
Those are two subtlety different things, after all. :) One implies that
for each company, you actually know the set of components that need to
go on the page, but need to get the actual /parameters/ for those
components from some configuration.  The other implies that, for
instance, the company may at runtime add various types of fields to
their page config.

For the former scenario (you know the components for a given company,
but you just need to be able select based on company), you can render
the consistent components, and then for the custom components, do
something like:

<span jwcid="@RenderBlock" block="ognl:getBlock(company)"/>

.java:

public Block getBlock(Company c) {
  return (Block)
getRequestCycle().getPage(c.getBlockPageName()).getComponent(c.getBlockName());
}

Now you can have a separate page for each company which contains a block
which, in turn, contains the components for that company.

If it's the latter scenario, then I'd probably head down a path similar
to what jesse suggested. In reality, the type of components that the
user can add is going to be limited... select, text, checkbox, radio...
am I missing anything? :) So, yeah... I think jesse's idea would hold
well. So, you would do something like this:

<span jwcid="@Foreach" source="ognl:company.extraFields"
value="ognl:currentField">
  <span jwcid="@RenderBlock"
block="ognl:components[currentField.blockName]" field="ognl:currField"/>

</span>
<span jwcid="[EMAIL PROTECTED]">
   <span jwcid="@Insert"
value="ognl:components.foo.inserter.bindings['field'].object.label"/>
<span jwcid="[EMAIL PROTECTED]"
value="ognl:components.foo.inserter.bindings['field'].object.value/>
</span>

A couple of notes... here as well, the block doesn't have to be on the
same page as the RenderBlock. You could get fancy and have your field
specify the page name and block name, or whatever. Also note that the
finally-rendered component has the "inserter" parameter... very useful.
You can get at any informal parameters of the "RenderBlock" parameter
that way. (In fact, there's probably a shorter ognl path than the one I
put in, although the one I put in will work). So, you can pass whatever
objects along that you need to that way to configure the components.

HTH. (Hrm. Looks like I ended up spouting off, anyway :)

Robert

Jesse Kuhnert wrote:
> That sounds like one crazy set of requirements ;)
> 
> I don't know how you will possibly handle the layout issues involved, 
but it
> wouldn't be far-fetched to do something like(taken from
> 
http://jakarta.apache.org/tapestry/tapestry/ComponentReference/RenderBlock.html

> ):
> 
> <foreach looping element here>
> 
> <span jwcid="<your field type block name>@Block" >
>       <span jwcid="[EMAIL PROTECTED]" />
> </span>
> 
> <span jwcid="<your field type block name>@Block">
>       <span jwcid="[EMAIL PROTECTED]" />
> </span>
> 
> </for>
> 
> Your page would then hand out blocks depending on the type of field you 
need
> to render "for each" loop. I've used a similar technique for handling
> varying data type renders, but they were always based around rendering a
> custom component "form" configuration.
> 
> Ie if I had a classification system for ummm... "pets", I might have a
> different form component grouping for each pet:
> 
> Dog:
> <number of cats chased>
> <likes to be pet>
> <known to bite>
> 
> Cat:
> <number of dogs hissed at>
> <definitely hates everyone>
> 
> etc...
> 
> hope that helps..
> 
> jesse
> 
> On 1/26/06, [EMAIL PROTECTED] <[EMAIL PROTECTED]> 
wrote:
> 
>>We're neck deep in Tapestry 3.0.3 and are struggling with how to handle 
N
>>number of components in a form.
>>
>>(from thread, below) "I've found that anything you might think of 
solving
>>by using dynamic components can be solved as well or better by some 
other
>>method which
>>tapestry /does/ provide."
>>
>>If this is true, how would Tapestry solve the following problem?
>>
>>(basically this is the problem of putting N text fields in a form, where 
N
>>is derived from a db/sml configuration)
>>
>>We have a page containing a form, let's say it's an order form.  The 
user
>>is entering data for various companies, not just their employer.  The 
form
>>contains a bare minium of form elements / components, e.g., name, 
address,
>>item, quantity, price, etc., and these are common to all companies.
>>
>>However, depending on the company for whom we are filling out the form,
>>there may be additional fields.  There can be from zero to n additional
>>fields.  These additional fields are configured in a database or XML 
file.
>>How do I dynamically generate the addittional, company-specific
>>components on the form?  Note, this is important because each component
>>must use Tapestry's validation/delegate mechanism to perform server-side
>>validation.
>>
>>Currently, we have resorted to doing client-side validation on the
>>custom/dynamic form elements & then letting Tapestry perform server-side
>>validation on the static form components.  From a usibility stance, this
>>is unacceptable.  But we're stumped on how to have N components in our
>>form.  We must fulfill this requirement.  Yes, we could create 20 extra
>>components & use conditionals, but we don't want to be limited to any
>>number--there really could be 50 or 100 or more.
>>
>>Thanks,
>>  - Mike
>>
>>
>>---------------------------------------------------------------------------------------
>>Re: instantiating components directly
>>Robert Zeigler
>>Thu, 12 Jan 2006 12:28:46 -0800
>>
>>Yes... but you don't need to use dynamically added components to
>>accomplish that. You can accomplish it using a static structure, 
including
>>direct links. Or, your "tree" component implements the "IDirect"
>>interface. Then it generates the urls needed, and provides the necessary
>>listener and gets called-back automatically by the direct service. I 
think
>>there are some pretty good reasons to keep the component tree static. 
For
>>one thing, page objects are very expensive to create, which necessitates
>>(the oft maligned) page pooling. However, because you are pooling the
>>pages, the component tree MUST be static, because you can't guarantee 
that
>>the same page instance will be used the /next/ time the page is 
rendered.
>>There may be ways around that, but generally, I've found that anything 
you
>>might think of solving by using dynamic components can be solved as well
>>or better by some other method which
>>tapestry /does/ provide.
>>(That said, I won't deny wishing for being able to add components at
>>runtime on occasion. :)
>>
>>Robert
>>
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


Reply via email to