cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Sylvain Wallez <>
Subject Re: CForms Wizards
Date Mon, 15 Nov 2004 10:49:18 GMT
Daniel Fagerstrom wrote:

> Sylvain Wallez wrote:
>> Daniel Fagerstrom wrote:
> <snip/>
>>> Take a look at 
>>> where I have 
>>> enhanced work of Jonas Ekstedt so that one can do the kind of things 
>>> you asked for in the section about multi page forms in 
>>> So now it is possible to write CForms wizards by writing javascript 
>>> FSMs in the form definition using widget states. Or if you prefer, 
>>> by using flowscript back-button magic, and automatic selection of 
>>> what is validated based on what widgets you use in your template.
> Before I answer I'd like to point out that the bugzilla entry 
> illustrates two different things: flowscript "back-button magic" for 
> CForms and "validating what's in the template". Even if they in 
> combination IMO is a very promising candidate for having easy to wrte 
> multi page wizards in Cocon, they can be evaluated and used separatly.


> The flowscript stuff can be used together with widget states and could 
> be put into the trunk quite soon. A better metod for communicating 
> between the form and the flow script form handling code is needed 
> first. And I would also prefer to discuss the code and idea a little 
> bit first as it is intricate stuff. I will hopefully find time to 
> write an RT about the details soon.
> The "validating what's in the template" is IMO promising stuff and is 
> part of the CForms refactoring vision, that I talk about all the time 
> ;) But it is not ready for prime time yet. It is on going work.
>> There's a problem by validating what's in the template, IMO: this 
>> means that if the template is wrong, i.e. it misses some important 
>> widget defined by the form, the form will be incorrectly considered 
>> valid.
> Sure, IMO, you should always do a complete validation of _all_ widgets 
> before binding your form model to business data. There is the same 
> problem with widget states, you can have faulty event logic so that 
> you happens to hide some subtree during all states in the filling in 
> of the multi form.

Sure, but forgetting a whole subform within the event handling is less 
likely to happen than forgetting a single widget in the template. 
Furthermore, we can automate the subform navigation and validation, not 
only using <fd:wizard-action> but also using a new <fd:wizard> container 
that would automatically iterate among its children (which are likely to 
be <fd:struct> themselves).

> So, partial validation is used after each sub form in a wizard to give 
> immediate feedback. Then complete validation is done before using the 
> data. This is IMO the only safe option.

Exactly. But with template-driven wizard, you don't know where to go 
back if validation fails, whereas with definition-driven wizard, we 
simply redisplay the first invalid subcontainer. Or will you keep the 
list of used widgets with each step to find where a widget was firstly used?

>> Also, this behaviour only validates terminal widgets and no container 
>> widgets, which may carry some additional semantic checks like row 
>> uniqueness in a repeater.
> I'm aware of that as you can see in the bugzilla comment, and have not 
> thought that much about of it yet. One possibillity could be to let 
> value change "bubble" and let the container validators trigger on 
> child events. Any other ideas? I have not used container validators 
> yet, so I don't know that much about the use cases.

The current behaviour is recursive depth-first validation, i.e. a 
container triggers its own validators if all of its children are valid. 
I'm not sure bubbling could do the trick, as validation is handled 
separately from value-changed events, and we have to know where to stop 
bubbling. Bubbling up to the Form is likely not to work, as validation 
will fail on required fields that weren't in the template.

>> So although reading only widgets present in the original template may 
>> make sense, using that same widget list for validation is wrong. 
> Wrong. based on missing parent validation, or are there further reasons?

Yes, missing parent validation, and also the difficulty to detect faulty 
wizard pages and going back to them.

>> And again, registering this list of used widgets will become useless 
>> once widgets don't reset their values if their corresponding 
>> parameter is not present. I'm just waiting for the release before 
>> adding this new feature.
> Wrong and useless, you are using strong words Sylvain ;)

Well, yes because I see too many potential problems with this approach 
compared to the apparent simplicity it brings!

> If we can find a good solution of the parent validation problem, it is 
> rather usefull as we only need to tell about what widgets that we want 
> to validate once, in the view. Furthermore, even if I have no 
> immediate need for that, Jonas has shown that it makes it safe to use 
> a form frame work without having a form model in between the view and 
> the "business data".

Uh, no form model and still safe? I missed that...

>> Furthermore, flowscript back-button magic implies that we can only 
>> navigate back to the previous screen, and not in an arbitrary screen 
>> in the sequence.
> I implemented it in that way because I didn't had any use cases for 
> something more complicated. But you can send a "go back" message 
> together with a web continuation id to the form handler, by using that 
> the form handler can first save the current form data and then jumping 
> to any previous continuation. I'll explain the details in the above 
> promised "back-button magic" RT.

Things I don't like in this back-button magic:
- not all forms are wizard, rather the contrary. So having the wizard 
engine plugged in deep in CForms doesn't seem good to mee.
- it's magic, meaning the fact that the user can go back is even not 
apparent in the flowscript.
- it is limited to CForms only, meaning if other pages are placed 
inbetween (regular pages, other form handling, etc), they cannot 
participate in the wizard navigation.

We had such a discussion one year ago and at that time I proposed a 
wizard API [1] that makes use of bookmarks and PageLocal (that did not 
existed at that time). Such a wizard API would make the fact that a 
wizard-style interaction is setup explicit in the flowscript, without 
requiring much more coding, especially if we integrate CForms in the 
wizard API (rather than putting wizards in CForms).


function myWizard() {

    var form = new Form("blah.xml");

    var wizard = new Wizard();
    // allow showForm() to handle wizard navigation


    cocoon.sendPageAndWait("dialog.html", {wizard:wizard}");


    ... etc ...

The "markStep()" method is used to create a named continuation that can 
later be used to go back to any previous step in the navigation chain.

This approach allows to use wizard-style navigation with any kind of 
page, and not only forms. And if we want to go further, we could even 
make wizards a built-in feature of flowscript, i.e. add some methods to 
the "cocoon" object such as:
- cocoon.startWizard()
- cocoon.wizardStep(name)
- cocoon.finishWizard() // to invalidate all continuations in a wizard

The backwards navigation could then be handled automatically by the 
sendPageAndWait() method. Yes, that would be magic as you'll have 
nothing special to write, except "cocoon.startWizard()", which 
implictely says "let's start the magic, I know it will happen from now on".

That proposal may seem rather in opposition with the state-driven wizard 
sample I wrote, but I think not. Flowscript-level wizards are useful for 
complex interactions and navigation, whereas form-level wizards are 
useful to simply split a large form throughout several screens, when 
there is no need for navigation decision (i.e. the next screen doesn't 
depend on values in the current or previous screens). Think of it as a 
server-side handling of form tabs (see the form1 sample in CForms).

>>> But in the later case you miss the joy of writing all the javascript 
>>> event handling code ;)
>> Sure, but you still need a lot of <jx:if> in the template, wheareas 
>> activating/hiding groups means you just declare all groups 
>> (fd:struct) in the template and it adapts automatically.
> Either you decide what should be shown together in the view or in the 
> model. You get <jx:if> (or separate templates), in the first case and 
> fd:structs in the second. IMHO it is better to code view aspects, like 
> what should be shown in the same sub view, in the view than in the 
> model. It will be easier to reuse the model for several views, e.g. 
> specialist view (one screen), wizard view and pda wizard view, if you 
> don't put the view groupings in the model.

Mmmh... I agree and disagree at the same time :-)

The various widgets that will be presented in a multi-page navigation 
will be grouped by their relations, i.e. a page will show a consistent 
set of related data. And when displaying the same data in a single page, 
it's very likely that the same grouping will be used to lay out the 
page, using e.g. <fieldset> elements.

In that case, the difference between the multi-page and single-page 
templates will be that only one of these groups will be visible a one 
time in the multi-page template.

>> And while writing the sample, some new <fd:wizard-action> widgets 
>> with builtin event handling popped up in my head, just like we have 
>> today <fd:repeater-action> and <fd:row-action>. No more javascript 
>> event-handling, no <jx:if>.
> Seem like good ideas.
>> One last point also: being able to split a form across multiple page 
>> may allow for multi-channel forms, where the full form is shown on a 
>> regular browser, whereas it is split across several pages for PDAs or 
>> phones. That split can be decided by the view, choosing the 
>> appropriate template depending on the browser type, with no impact on 
>> the flowscript which will just have a single form.showForm().
> :) So we booth belive that multi chanel wizards mainly should affect 
> the view. But you want AFAIU to have event based flow control in the 
> model and I prefer to have flowscript based flow control.

The event-driven model allows to have the *exact same* flowscript 
whether the form is displayed in a single page or across multiple pages. 
This is important in a multi-channel application as, although the view 
will be different, the application logic should be the same whatever 
kind of browser the user has.

> We introduced flowscripts in Cocoon once because we thought that it 
> was a better way to control flow in e.g. wizards than using FSMs, were 
> we wrong?

Certainly not! But there may be a need for lower-level controllers, 
which in that case is implemented in a event-driven way by using 
continuations to handle those events.

> A problem with coding where we are in the wizard, booth as a widget 
> state and a flowscript state (i.e. where we are in the form handling 
> loop), is that previous continuations might get inconsistent. What 
> happens if the user happens to use the browser back button in a widget 
> state based wizard e.g.

Using a single continuation within the form.showForm loop (which would 
therefore no more be formally a loop) may be a way to handle this.

> Anyway, thanks for evaluating the proposal and comming with 
> constructive critic. I have some interesting new things to consider :)




Sylvain Wallez                                  Anyware Technologies 
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }

View raw message