You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@wicket.apache.org by Eelco Hillenius <ee...@gmail.com> on 2006/11/28 23:14:37 UTC

traversing form components

Currently, we traverse children of Forms pre-order. It would imo
actually be nicer to traverse post-order so that if you would create
nested form components - not a common use case, but possible - the
children would be updated before the parent, so that the parent can
use the updated values of the children.

WDYT?

Eelco

Re: traversing form components

Posted by Eelco Hillenius <ee...@gmail.com>.
Yeah. I'm not sure what my problem was yesterday, but I don't have it
now. For some reason I got crazy values in those validators. But this
morning after a night of sleep that all seems to be gone. I couldn't
think of why that would happen anyway.

Eelco

> I don't get why you have to cast.
> i don't: NumberValidator.range(0, 10);
> works fine. It sees that it is mapping on the long method
> when i do this:
>
> NumberValidator.range(0d, 10d);  it maps on the double method
> and also this:
> NumberValidator.range(0.1, 10); maps on the double
>
> because you shouldn't have to cast because a int fits into a double (you
> don't loose anything)
>
> johan
>
>

Re: traversing form components

Posted by Eelco Hillenius <ee...@gmail.com>.
On 11/29/06, Igor Vaynberg <ig...@gmail.com> wrote:
> what if the parent is disabled - then the traversal should not go to
> children.

Yep. But that's not rocket science.

> there are plenty of usecases for both traversal modes - i wouldnt change the
> default because there might be a lot of things that depend on it and they
> might start failing silently and be really hard to track down.

Like what? I'm talking about form traversal here, not the generic
component traversal, and my bet is that not that many people actually
use nested form components much, simply because it is relatively hard
to implement right now. The use case you'd have are like the example I
gave earlier this thread, and here the reversal of traverse order
wouldn't break anything. And it is unlikely that a child needs to get
the updated value (the SUBMITTED value) from the parent because most
likely that parent - like my example - doesn't actually get user input
but rather aggregates from the childs.

> maybe the best thing to do is not to have the form traverse children and
> call individual steps like it does now, but instead invoke a single workflow
> method that encapsulates the traverasal logic for its children and can be
> overridden.

We could gather the components to visit as a list or stack first (that
would probably be necessary for post-order traversal anyway) and then
do the actual traversal in another method.

Eelco

Re: traversing form components

Posted by Igor Vaynberg <ig...@gmail.com>.
what if the parent is disabled - then the traversal should not go to
children.

there are plenty of usecases for both traversal modes - i wouldnt change the
default because there might be a lot of things that depend on it and they
might start failing silently and be really hard to track down.

maybe the best thing to do is not to have the form traverse children and
call individual steps like it does now, but instead invoke a single workflow
method that encapsulates the traverasal logic for its children and can be
overridden.

-igor


On 11/29/06, Johan Compagner <jc...@gmail.com> wrote:
>
> i don't know exactly
> Are there cases that the parent wants already data of the child?
> If nobody can think about something for that then i don't mind.
>
> johan
>
>
> On 11/29/06, Eelco Hillenius <ee...@gmail.com> wrote:
> >
> > But now the real question: what about that traversal?
> >
> > Eelco
> >
> > On 11/28/06, Johan Compagner <jc...@gmail.com> wrote:
> > > >
> > > >
> > > >
> > > > with validation this time. Note the (double) casts.. they suck and
> > > > should be solved by adding methods that take ints. Anyone up to
> that?
> > >
> > >
> > >
> > > I don't get why you have to cast.
> > > i don't: NumberValidator.range(0, 10);
> > > works fine. It sees that it is mapping on the long method
> > > when i do this:
> > >
> > > NumberValidator.range(0d, 10d);  it maps on the double method
> > > and also this:
> > > NumberValidator.range(0.1, 10); maps on the double
> > >
> > > because you shouldn't have to cast because a int fits into a double
> (you
> > > don't loose anything)
> > >
> > > johan
> > >
> > >
> >
>
>

Re: traversing form components

Posted by Johan Compagner <jc...@gmail.com>.
i don't know exactly
Are there cases that the parent wants already data of the child?
If nobody can think about something for that then i don't mind.

johan


On 11/29/06, Eelco Hillenius <ee...@gmail.com> wrote:
>
> But now the real question: what about that traversal?
>
> Eelco
>
> On 11/28/06, Johan Compagner <jc...@gmail.com> wrote:
> > >
> > >
> > >
> > > with validation this time. Note the (double) casts.. they suck and
> > > should be solved by adding methods that take ints. Anyone up to that?
> >
> >
> >
> > I don't get why you have to cast.
> > i don't: NumberValidator.range(0, 10);
> > works fine. It sees that it is mapping on the long method
> > when i do this:
> >
> > NumberValidator.range(0d, 10d);  it maps on the double method
> > and also this:
> > NumberValidator.range(0.1, 10); maps on the double
> >
> > because you shouldn't have to cast because a int fits into a double (you
> > don't loose anything)
> >
> > johan
> >
> >
>

Re: traversing form components

Posted by Eelco Hillenius <ee...@gmail.com>.
But now the real question: what about that traversal?

Eelco

On 11/28/06, Johan Compagner <jc...@gmail.com> wrote:
> >
> >
> >
> > with validation this time. Note the (double) casts.. they suck and
> > should be solved by adding methods that take ints. Anyone up to that?
>
>
>
> I don't get why you have to cast.
> i don't: NumberValidator.range(0, 10);
> works fine. It sees that it is mapping on the long method
> when i do this:
>
> NumberValidator.range(0d, 10d);  it maps on the double method
> and also this:
> NumberValidator.range(0.1, 10); maps on the double
>
> because you shouldn't have to cast because a int fits into a double (you
> don't loose anything)
>
> johan
>
>

Re: traversing form components

Posted by Johan Compagner <jc...@gmail.com>.
>
>
>
> with validation this time. Note the (double) casts.. they suck and
> should be solved by adding methods that take ints. Anyone up to that?



I don't get why you have to cast.
i don't: NumberValidator.range(0, 10);
works fine. It sees that it is mapping on the long method
when i do this:

NumberValidator.range(0d, 10d);  it maps on the double method
and also this:
NumberValidator.range(0.1, 10); maps on the double

because you shouldn't have to cast because a int fits into a double (you
don't loose anything)

johan

Re: traversing form components

Posted by Eelco Hillenius <ee...@gmail.com>.
In case anyone was playing with it, that component wasn't done yet...
it needed this:

	@Override
	protected void onAttach() {
		date = (Date) getModelObject();
		if (date != null) {
			Calendar c = Calendar.getInstance();
			c.setTime(date);
			hours = c.get(Calendar.HOUR);
			minutes = c.get(Calendar.MINUTE);
			amOrPm = (c.get(Calendar.AM_PM) == Calendar.AM) ? AM_PM.AM : AM_PM.PM;
		}
		super.onAttach();
	}

and this is the improved init:

	private void init() {

		setType(Date.class);
		add(dateField = new TextField("date", new PropertyModel(this,
"date"), Date.class));
		add(new DatePicker("picker", dateField, newDatePickerSettings()));
		add(hoursField = new TextField("hours", new PropertyModel(this,
"hours"), Integer.class));
		hoursField.add(NumberValidator.range((double)0, (double)12));
		add(minutesField = new TextField("minutes", new PropertyModel(this,
"minutes"), Integer.class));
		minutesField.add(NumberValidator.range((double)0, (double)60));
		add(amOrPmChoice = new DropDownChoice("amOrPmChoice", new
PropertyModel(this, "amOrPm"), Arrays.asList(AM_PM
				.values())));
	}

with validation this time. Note the (double) casts.. they suck and
should be solved by adding methods that take ints. Anyone up to that?
Bed time here.

Eelco

On 11/28/06, Eelco Hillenius <ee...@gmail.com> wrote:
> On 11/28/06, Eelco Hillenius <ee...@gmail.com> wrote:
> > Currently, we traverse children of Forms pre-order. It would imo
> > actually be nicer to traverse post-order so that if you would create
> > nested form components - not a common use case, but possible - the
> > children would be updated before the parent, so that the parent can
> > use the updated values of the children.
> >
> > WDYT?
> >
> > Eelco
>
> For example, this would make a Date/Time component:
>
> public class DateTimeField extends FormComponentPanel {
>
>         private static enum AM_PM {
>                 AM, PM
>         }
>
>         private AM_PM amOrPm = AM_PM.AM;
>         private DropDownChoice amOrPmChoice;
>         private Date date;
>         private TextField dateField;
>         private Integer hours;
>         private TextField hoursField;
>         private Integer minutes;
>         private TextField minutesField;
>
>         public DateTimeField(String id) {
>                 super(id);
>                 init();
>         }
>
>         public DateTimeField(String id, IModel model) {
>                 super(id, model);
>                 init();
>         }
>
>        // getters & setters omitted
>
>         @Override
>         public void updateModel() {
>
>                 dateField.updateModel();
>                 hoursField.updateModel();
>                 minutesField.updateModel();
>
>                 if (date != null) {
>                         Calendar c = Calendar.getInstance();
>                         c.setTime(date);
>                         if (hours != null) {
>                                 c.set(Calendar.HOUR, hours);
>                                 c.set(Calendar.MINUTE, (minutes != null) ? minutes : 0);
>                         }
>                         if (amOrPm == AM_PM.PM) {
>                                 c.set(Calendar.AM_PM, Calendar.PM);
>                         } else {
>                                 c.set(Calendar.AM_PM, Calendar.AM);
>                         }
>                         setModelObject(c.getTime());
>                 }
>         }
>
>         protected DatePickerSettings newDatePickerSettings() {
>                 return new DatePickerSettings();
>         }
>
>         private void init() {
>
>                 add(dateField = new TextField("date", new PropertyModel(this,
> "date"), Date.class));
>                 add(new DatePicker("picker", dateField, newDatePickerSettings()));
>                 add(hoursField = new TextField("hours", new PropertyModel(this,
> "hours", Integer.class)));
>                 add(minutesField = new TextField("minutes", new PropertyModel(this,
> "minutes", Integer.class)));
>                 add(amOrPmChoice = new DropDownChoice("amOrPmChoice", new
> PropertyModel(this, "amOrPm"), Arrays.asList(AM_PM
>                                 .values())));
>         }
> }
>
>
> I update the nested components manually there, but it would be much
> nicer if I would have to do it; less work/ more elegant and they
> wouldn't be updated twice.
>
>
> Eelco
>

Re: traversing form components

Posted by Eelco Hillenius <ee...@gmail.com>.
On 11/28/06, Eelco Hillenius <ee...@gmail.com> wrote:
> Currently, we traverse children of Forms pre-order. It would imo
> actually be nicer to traverse post-order so that if you would create
> nested form components - not a common use case, but possible - the
> children would be updated before the parent, so that the parent can
> use the updated values of the children.
>
> WDYT?
>
> Eelco

For example, this would make a Date/Time component:

public class DateTimeField extends FormComponentPanel {

	private static enum AM_PM {
		AM, PM
	}

	private AM_PM amOrPm = AM_PM.AM;
	private DropDownChoice amOrPmChoice;
	private Date date;
	private TextField dateField;
	private Integer hours;
	private TextField hoursField;
	private Integer minutes;
	private TextField minutesField;

	public DateTimeField(String id) {
		super(id);
		init();
	}

	public DateTimeField(String id, IModel model) {
		super(id, model);
		init();
	}

       // getters & setters omitted

	@Override
	public void updateModel() {

		dateField.updateModel();
		hoursField.updateModel();
		minutesField.updateModel();

		if (date != null) {
			Calendar c = Calendar.getInstance();
			c.setTime(date);
			if (hours != null) {
				c.set(Calendar.HOUR, hours);
				c.set(Calendar.MINUTE, (minutes != null) ? minutes : 0);
			}
			if (amOrPm == AM_PM.PM) {
				c.set(Calendar.AM_PM, Calendar.PM);
			} else {
				c.set(Calendar.AM_PM, Calendar.AM);
			}
			setModelObject(c.getTime());
		}
	}

	protected DatePickerSettings newDatePickerSettings() {
		return new DatePickerSettings();
	}

	private void init() {

		add(dateField = new TextField("date", new PropertyModel(this,
"date"), Date.class));
		add(new DatePicker("picker", dateField, newDatePickerSettings()));
		add(hoursField = new TextField("hours", new PropertyModel(this,
"hours", Integer.class)));
		add(minutesField = new TextField("minutes", new PropertyModel(this,
"minutes", Integer.class)));
		add(amOrPmChoice = new DropDownChoice("amOrPmChoice", new
PropertyModel(this, "amOrPm"), Arrays.asList(AM_PM
				.values())));
	}
}


I update the nested components manually there, but it would be much
nicer if I would have to do it; less work/ more elegant and they
wouldn't be updated twice.


Eelco