Sylvain Wallez wrote:
I understand your point and went through it also. But remember an
wow! a historic event (I made myself clear at first attempt)
And without a body-language video attachment ;-)
important point : repeaters dynamically create widgets, meaning you can't attach an event listener directly on the widget contained in a repeater, otherwise similar widgets in different rows will not have the same behaviour.
Now a WidgetEvent contains the source widget along with the FormContext that was used when it was generated. And I also added a FormContext.getForm() to access the root of the widget tree.
sounds good, it's pretty much what I understood/expected
so it could change state-information in the model (userData area or hidden widgets) and as such it becomes available to the use-case-controller since it has a point to the form and can expect it.
Yep. But using hidden widgets for this doesn't seem the right solution for me. I thought of adding get/setAttribute on Widget (or only on Form?), but did not found a real need for it now. Maybe it's needed after all...
yes there is: as I explained there is obvious need for
1/ event listeners that only are responsible for dynamic effects on the 'view' (which can be handled by this)
2/ but in the general case there is obviously also need for event-listeners that hook up into the 'controller'
for the latter I find get/setAttribute only marginally better then hidden widgets: both add a loose contract where a strong one is possible, thus removing guidance from compile time check and introducing possible errors...
Mmmh... hidden widgets may actually be better in that case since they are typed, and can be checked at runtime since they have to be declared in the form definition.
What I don't like much, however, is that we introduce app-related things in the form definition. Or perhaps we should define a new <app-data> widget that is never sent to the client nor read from the request ?
<snip/>
well what I thought I read was: you seemed to 'queue' up events in a channel to be sent out only later
but this clarification makes me see you send them back over the originating widget, which would probably not be neccessary if we use the event-dispatchers which are defined on the form level any way, no?
then form processing would allow all widgets to post their events in their assigned queue where they are hold untill processing is completed and thus only sent out at a moment where all widgets were in a new state (which is mucho important, didn't realize until you mentioned it, nice one to catch!)
Event-dispatcher may prove useful when there's a need to link the use-case controller to the widget tree, but I don't think everything should go through these dispatchers. In most cases, event handling will not require this relation to the controller and having to define a dispatcher for every widgets wanting to handle events will quickly become overly verbose.
So I think we need both. And as I alreday mentioned, we can consider sending events to an event-dispatcher as a special case of event listener.
Not exactly : events are registered on the FormContext and broadcasted back to their originating widget once the current processing phase is finished. As we speak, I'm listing these phases and found the following :
- load (binding)
- readFromRequest (may be this should be merged with load in a "get value" phase ?)
- validate,
- save (binding)
ah, you mean each of these processing-phases could possibly result in events been thrown, so not only the readFromRequest?
Yes. For example, we can imagine that a (yet-undefined) ValidationChangedEvent on a purchase order ID field can lead to change the contents of the repeater containing the items of the purchase order. The ValueChangedEvent won't be enough in that case since we must not only ensure that the ID is correct, but also that it actually exists in the purchase-order database.
JSF seems to resend all events at every phase (unless I missed something). I don't know if this is good, as it may be difficult for an EventHandler to know if it already has handled a given event.
<snip/>
I'm thinking of adding a new "submit-on-change" attribute on <wi:styling>, but I'm wondering if this belongs to the view or to the form definition. Seems better on the view.
yep, that's what Bruno did, if you like, I can check how he did it.
onchange="getForm(this).submit()" ? Maybe with an additional hidden field indicating that it's not a "normal" submit ?
yep, and AFAIR the hidden field was just the action-widget itself!
I came to something a bit different : the hidden field contains the ID of the widget that triggered the submission if it's not a "normal" submit form element (like <input type="submit">). This allows to easily determine server-side where the submit originates from.
Anyway, I'd be interested in knowing Bruno's approach.
<snip/>
what I meant is that the control itself would be remembering what happened to the rows in between two calls to some method that sets a 'resetRowModificationInfo()' which would then be called to set some revision-point between which the control would be remembering some metadata on each of the rows.
of course this borrows from the current way binding is used: once at the start (load) and once at the end (save) of the use case.
Can't this directly be implemented in the repeater itself ? The repeater tracks row modifications, and the binding is responsible to call resetRowModificationInfo(), recordRowModifications(true) and getRowModificationInfo()
yep, that is what I was thinking and then the getRowModificationInfo() could provide for a interateNewRows() iterateDeletedRows() iterateStillExistingRows() to make it ever more easy ;-)
No problem : once we say that a repeater can record modifications, we can define the API necessary to easily use this information.
looking at how this often maps to talking to a (persistency) backend system I'm not really tempted into changing this usage pattern for now
of course if we agree that stacking up these changes are not part of the concern of the widget itseld, then we will need a listener of
I agree that making it a concern of the repeater-widget itself just makes things a lot easier
However I'm still somewhat doubthing if we should.
question: Is 'we like it for the binding' enough of a justification to add this concern to the repeater-widget ?
(of course: if it is useful to the binding it will also be useful to people that don't use the binding but are handling the changes programatically, right?)
also adding the recordRowModificationInfo(true) helps me see we could just do it: it indicates that it really is an exteral concern we can add dynamically (I like)
Mmmh... not sure I understood all the details here. Do you mean that repeater recording could simply be a particular implementation of an RepeaterEventListener ? Yes. This would separate the recording concern from the widget itself.
This RecordingListener could even be created by the repeater binding itself.
<snip/>
sorry here, I started mixing use-case controller (i.e flow-script or apple) and the eventListener... as shown above they often go hand in hand: some eventListeners only affect the view itself, but some of them really have to callback into the state of the use-case.
Ah, ok, I understand. Then either the event-dispatcher stuff or adding attributes to widgets may be the solution.
yes, but we prefer... ;-)
... <wd:app-data> widgets for typing and runtime checks ? No problem !
Some more thoughs that came to me :
1 - what about a <on-load> event handler that would be called once the widget tree is first set up ?
2 - I'd like to add a "disabled" property to <action> widgets. Depending on what happens on the form, we may want to allow or not certain actions.
3 - I'd like to find an easy way to indicate if an <action> should terminate the form or if it's a intra-form action (such as add-row on a repeater) which leads to redisplay the form.
4 - similarily, I'd like to have a way to indicate if an <action> should try to validate the values. For example a "cancel" button will terminate the form without trying to validate it.
For points 3 & 4, two solutions come to my mind :
- add 2 new attributes on <action> : validate="true|false" and end-form="true|false". Of course if validate="true", the form is redisplayed if validation fails even if end-form="true".
- distinguish <action> and <submit> : an <action> would not terminate the form while a <submit> would. Both would have a "validate" attribute, but its default value would be "false" for <action> and "true" for <submit>.
What do you think ?
Sylvain
-- Sylvain Wallez Anyware Technologies http://www.apache.org/~sylvain http://www.anyware-tech.com { XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects } Orixo, the opensource XML business alliance - http://www.orixo.com
