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]