Dynamic set of form fields

1 view
Skip to first unread message

Evan Broder

unread,
Jul 15, 2008, 5:46:17 PM7/15/08
to toscawidge...@googlegroups.com
I'm working on an application where I want the fields in a form to be
generated when the form is displayed. (I want to have a field for each
user in my database). Can I do this somehow through the update_params
hook or something like that?

- Evan

Joseph Tate

unread,
Jul 15, 2008, 10:19:20 PM7/15/08
to ToscaWidgets-discuss
Take a look at the address sample[1], but make your form ALL repeated
elements. The only trick is that you'll have to tell the form how
many elements you want when you call display(). To do this you'll
have to either override the display() method in your form, or pass a
kw dict to the stock display() as in the thread here:
http://groups.google.com/group/turbogears/browse_thread/thread/4439885b7080b5d/54ccb6ef4306d8ea

[1] http://toscawidgets.org/documentation/tw.forms/modules/fields/forms.html#an-example

Evan Broder

unread,
Jul 15, 2008, 10:47:58 PM7/15/08
to toscawidge...@googlegroups.com
I've looked at those examples. In this particular case, though, I want
the labels/values to be different for each instance of the form, which
the plain FormFieldRepeater doesn't seem to be able to support.

- Evan

Alberto Valverde

unread,
Jul 16, 2008, 11:52:54 AM7/16/08
to toscawidge...@googlegroups.com

>
> I've looked at those examples. In this particular case, though, I want
> the labels/values to be different for each instance of the form, which
> the plain FormFieldRepeater doesn't seem to be able to support.

As I've just said in a reply to Joseph's post labels cannot yet be
overriden on update_params since it's the form that renders it, not the
field. However, you might want to try to make a TextField (or whatever)
subclass that displays it's own labels and tell the form not to display
them (I think Paul applied a patch to do just that, take a look at the
Form's params list see if you find anything.

Alberto

Evan Broder

unread,
Jul 17, 2008, 12:05:52 AM7/17/08
to toscawidge...@googlegroups.com
Alberto Valverde wrote:
> As I've just said in a reply to Joseph's post labels cannot yet be
> overriden on update_params since it's the form that renders it, not the
> field. However, you might want to try to make a TextField (or whatever)
> subclass that displays it's own labels and tell the form not to display
> them (I think Paul applied a patch to do just that, take a look at the
> Form's params list see if you find anything.
>
> Alberto
update_params gets called for forms themselves, right? Could I somehow
initialize the children of a form in update_params? I think I tried a
bunch of things and couldn't make this work...

- Evan

Alberto Valverde

unread,
Jul 18, 2008, 6:12:23 AM7/18/08
to toscawidge...@googlegroups.com

>
> Alberto Valverde wrote:
>> As I've just said in a reply to Joseph's post labels cannot yet be
>> overriden on update_params since it's the form that renders it, not the
>> field. However, you might want to try to make a TextField (or whatever)
>> subclass that displays it's own labels and tell the form not to display
>> them (I think Paul applied a patch to do just that, take a look at the
>> Form's params list see if you find anything.
>>
>> Alberto
> update_params gets called for forms themselves, right?

Yes, it is called for every widget

>Could I somehow
> initialize the children of a form in update_params? I think I tried a
> bunch of things and couldn't make this work...

No, all children/fields must be known at widget initialization time since
they need to be grafted into a tree structure for correct "name" attr.
generation (for input widgets) and "id" attr generation (for all widgets),
a validator created for input widgets and many other things.

I think that the Widget's docstring explains something about it.

Probably the best you can do in this situation is to mimic the label with
a widget you can send a value to with the text, put it in a fieldset or
some container and then use a widget repeater to repeat each container as
a row.

Alberto

Evan Broder

unread,
Jul 23, 2008, 3:57:03 AM7/23/08
to toscawidge...@googlegroups.com
Alberto Valverde wrote:
> Probably the best you can do in this situation is to mimic the label with
> a widget you can send a value to with the text, put it in a fieldset or
> some container and then use a widget repeater to repeat each container as
> a row.
>
> Alberto

Ok, so I've spent a couple hours fighting with this, and I could use
some more advice. Specifically, it's not just good enough for me to be
able to control the labels and lengths of a list of input fields; I also
need some way to map each input field back to a row in my database.

To outline the basic application, I'm asking for a percentage for each user.

Here's the form declaration I have right now:
> from tw import forms
> from tw.api import WidgetsList
>
> from sample import model
> from sample.model import meta
>
> class PercentageField(forms.TextField):
> template = 'percentage_field'
> suppress_label = True
> label_text = ''
>
> class PercentageFieldSet(forms.ListFieldSet):
> suppress_label = True
>
> class fields(WidgetsList):
> percentage = forms.FormFieldRepeater(
> widget=PercentageField())
>
> def update_params(self, d):
> users = meta.Session.query(model.User)
>
> if 'child_args' not in d:
> d['child_args'] = dict()
>
> d['child_args']['percentage'] = dict(repetitions=users.count(),
> child_args=[])
>
> for i, user in enumerate(users):
> d['child_args']['split']['child_args'].append(
> dict(label_text=user.name))
>
> return super(PercentageFieldSet, self).update_params(d)

The percentage_field template is basically the label code from the
normal ListFieldSet plus a TextField (I'm using mako):
> <%namespace name="tw" module="tw.core.mako_util"/>\
> <label ${tw.attrs(
> [('id', '%s.label' % id),
> ('for', id),
> ('class', 'fieldlabel' + (' required' if is_required else ''))]
> )}>${tw.content(label_text)}</label>
> <input ${tw.attrs(
> [('type', context.get('type')),
> ('name', name),
> ('class', css_class),
> ('id', context.get('id')),
> ('value', value)],
> attrs=attrs
> )} />\

And this is very close to what I want. It currently outputs something like:
> <fieldset id="percentage" class="percentagefieldset">
> <legend>percentage</legend>
> <ul class="field_list" >
> <li class="even" id="percentage.container"
> >
> <label id="percentage_percentage-0.label"
> for="percentage_percentage-0" class="fieldlabel">Evan Broder</label>
> <input type="text" name="percentage.percentage-0"
> class="repeatedpercentagefield" id="percentage_percentage-0" value="" />
> <label id="percentage_percentage-1.label"
> for="percentage_percentage-1" class="fieldlabel">User 2</label>
> <input type="text" name="percentage.percentage-1"
> class="repeatedpercentagefield" id="percentage_percentage-1" value="" />
> <label id="percentage_percentage-2.label"
> for="percentage_percentage-2" class="fieldlabel">User 3</label>
> <input type="text" name="percentage.percentage-2"
> class="repeatedpercentagefield" id="percentage_percentage-2" value="" />
> <label id="percentage_percentage-3.label"
> for="percentage_percentage-3" class="fieldlabel">User 4</label>
> <input type="text" name="percentage.percentage-3"
> class="repeatedpercentagefield" id="percentage_percentage-3" value="" />
> </li>
> </ul>
> </fieldset>

But I have no way to connect percentage.percentage-3 back to User 4 in
my database. I'd like it to instead generate ids of the form
"percentage.percentage.3" instead, where the 3 is the ID field in the
database.

I realize that this question probably isn't coming off too well, since
I've had no luck attempting to grok ToscaWidgets' internals, but is
there any way to do this?

- Evan

Reply all
Reply to author
Forward
0 new messages