[TransWarp] peak.web.forms (was re: State of the Onion)
Phillip J. Eby
pje at telecommunity.com
Sat Aug 9 11:41:51 EDT 2003
At 04:38 PM 8/9/03 +0200, Roché Compaan wrote:
>* Phillip J. Eby <pje at telecommunity.com> [2003-08-08 19:30]:
> > I think that perhaps this would actually be cleaner if we use a slightly
> > different conceptual model, to divide up the work better. Let's change
> > what we've been calling a "widget set" into a "form definition",
> containing
> > "widgets", and then also have "forms". A form is an object that
> contains a
> > set of "fields", where a "field" is a data value and optional current
> > validation messages. (Actually, a field will have more than that, it will
> > also reference the underlying widget, and offer other convenient
> attributes
> > for use by the rendering machinery. But its value and messages will be
> > changeable, and the other stuff probably will be constant over the life of
> > the form instance.)
>
>This is roughly the conceptual model that Formulator uses.
Ah, good to know I'm reinventing solid technology, then. ;)
>During our
>discussion I thought that we don't really need "field" and that widgets
>can do all that you propose a field should do. I am still not convinced
>this is necessary separation, but I'll have to think about it some more.
Widgets shouldn't be mutable, but a widget class by itself will not contain
sufficient parameterization for its instances. Therefore, there are two
different objects at runtime: an object that describes the fixed properties
of the widget, and one that describes its state with respect to its current
usage within the web hit.
> > (By the way, I'm not entirely convinced that it's desirable to use the
> same
> > form definition to represent both viewing and editing, unless perhaps the
> > form definition can optionally allow you to define different widgets for
> > viewing and editing. The key would be "optionally", since if you are
> > required to always define two widgets for each field, you might as well
> > create two form definitions, no?)
>
>In my experience its quite common to use the same form for both. The
>form does not prescribe how the widgets should be rendered. In the case
>of the add/edit form you can call widget.renderInput() or just
>widget.render() and for the view you can call widget.renderView(). But I
>also think it should be very easy to manipulate the widgets in the form,
It should certainly be easy to change their *state*, and perhaps to
manipulate the form instance. But not the definition. I really want a
clear separation of class/factory from instance, with the former remaining
essentially immutable.
>precisely because there may be differences between "modes". Sometimes
>you just want to remove widgets on the edit form that are visible on the
>add form. If the differences are overwhelming then create another form.
I'd prefer the objects to control their own destinies here. If there are
things that should be different, this should be specified by the form or
widget definitions, not by application code at runtime. Otherwise, you are
tangling different concerns and making maintenance more difficult. If I
want to change the behavior of the form I should modify the form
definition, not code that is just using forms.
What if I need to make global changes to how forms behave in my app? I
would have to go through all the code. What if I use application
components written by somebody else? I should just be able to change the
form definition resource they use. Further, how can I change the behavior
of the form across different "skins", unless these matters are concealed
within the form definition itself? For example, if I make a "mobile"
version of my application, it may need many multi-page forms for things
that are single-page forms in my "desktop" version.
These are probably just some of the reasons that my subconscious mind used
to reach a decision that I want form behavior in a form definition, and
widget behavior in a widget definition, distinct from the current state of
either. :)
>I don't think the mode should be set for the form as a whole either. I
>often have forms where I call renderInput for some widgets and renderView
>for others. The widget render method that must be called should be a
>specified by the template as DOMlet parameter.
I'm somewhat curious about the application specifics, but I'm also
interested in seeing whether we could just allow form definitions to manage
this kind of thing on their own. Maybe it would require that we allow
custom subclasses in form definitions, but we would probably want to allow
that anyway. Definitely, I want this kind of UI-level behavior to be
replaceable on a per-skin basis.
> > Actually, it's tricky even for instances. It's possible that the page
> > we're rendering has edit forms for more than one object. So we can't say
> > "from the subject of our template" -- there might be more than one. We
> > need to get a form for some specific object, designated by the data
> path in
> > the DOMlet attribute.
>
>I don't understand why this is tricky in your mind. If I want to return
>a specific form for adding I will have an "add" method in a Decorator
>that returns a specific template that says "I want to work with form X".
>If the template is explicit about what form it wants why is it tricky?
Imagine a portal site, like My Yahoo, containing "portlet"
applications. It's possible that I might setup more than one instance of a
particular "portlet" type on "my" page, each with its own configuration
data. Maybe they are both "weather" portlets, and I've configured them to
display weather for different cities. So, they both are using the same
form definition, but at any given moment they will have different
data. Notice also that the page-level template is going to be a method of
a "portal page" object, not of the individual portlets, although the
portlets will certainly have their own templates.
Another scenario: consider an "invoice" being displayed, with several "line
items" that can be added/edited/deleted. I suppose, that this is also a
use case for nested form instances, and also for event-driven handling
defined in form definitions.
> > This seems to imply that form definitions found as attributes on a
> > decorator, need to play a dual role. Not only do they need to be the
> > constructor for a form instance, they also need to be able to look "up the
> > execution context" to see if an existing instance of that form definition,
> > *for a particular object*, already exists.
>
>I don't understand this.
It's probably not important; this e-mail is making me see that it was
trying to solve a much more superficial issue than the full scope of what
needs to be addressed. For example, our discussion so far has ignored
action buttons, like "delete" on a form where there are line-items
selectable with checkboxes. Or, complex inter-widget behavior, such as a
form where you select items from one listbox, and click to have them
transferred to another listbox, until you have the right ones in the right
order, and then you click another button to "do something" with your final
selection.
> > >Can the errors just be set
> > >on the request object? This will only work if we return the template in
> > >the same request, otherwise errors will have to be saved on the session.
> > >DOMLets rendering form errors should then look on both the request and
> > >session for errors.
> >
> > I'm confused by this, in that I don't understand how/when you would *not*
> > display the errors as part of the same operation.
>
>Only if you redirect instead of returning to an error page.
But why would you do *that*?
> > I *can* see the possibility that one might have such a thing as a
> > "multi-page form", but I think it would work like this... Imagine that
> you
> > have one large form definition, but the widgets on it have a "page"
> > property (or maybe the definition is divided into pages; whatever
> > works). Whenever you render the form, you put in hidden fields for any
> > page that's already passed, regular widgets for the page you're on, and
> > ignore any widgets for a page you've not yet reached. If there are
> errors,
> > you simply render the first "page" with errors in it.
>
>Hidden fields for lists? No thank you. I decidedly don't like dragging
>on hidden fields over multi-page forms - it just contaminates the
>namespace of a particular form and you have to turned marshalled data
>back into strings until the final page and then marshal them back to
>their intended types.
In order to be able to display or process the forms at all, you certainly
have to be able to marshal them in both directions, so I don't see that as
an issue. Since in the example I gave, you would never deal with the
hidden fields in any application code, or even in the form definition, I
don't see what the problem is.
As for "contaminates the namespace", note that I am saying there is *only
one form*, that happens to be rendered in pieces, so there was already a
global namespace and the application will only see that. If in one skin
the form is broken into 5 pages and in another skin it is one large form,
the application should not be able to tell the difference (or at least, it
certainly shouldn't *need* to tell the difference).
More information about the PEAK
mailing list