I have a form that will show up in a couple of different places in my
application. As it happens, the layouts provideed by TableForm or
ListForm aren't really what I want (developer's suffer from Bike Shed
momements too :-)).
It seems like the correct thing to do is to create a new FormWidget with
a custom template. Within that template though, what is a the right way
to get a hand on each of the fields in my form? The existing forms
widgets simple iterate over "fields" and drop them where the next field
goes. If I want to put *this* field *there*, and *that* field *over
there* how do I get it? It seems like I might be able to use the
field_for() method of Form but I don't know how to get at it within my
form's template?
Or, should I just dispense with the Form widget all together and simply
create .KID files with my layouts.
This is all with the current .9
Thanks for any insigt and apoligies if this is a hopelessly naive
question...
Keith
> It seems like the correct thing to do is to create a new FormWidget with
> a custom template. Within that template though, what is a the right way
> to get a hand on each of the fields in my form? The existing forms
> widgets simple iterate over "fields" and drop them where the next field
> goes. If I want to put *this* field *there*, and *that* field *over
> there* how do I get it? It seems like I might be able to use the
> field_for() method of Form but I don't know how to get at it within my
> form's template?
I'm trying three approaches: one is to hand code the form, then simply replace
values and names and ids there, the other is to use widgets inside this custom
template and the last one is to mix both.
As you can imagine, the first one is the less reusable and the one that is
harder to do. The second is the least flexible one since I only gain the
placement control. The third looks like the best approach since it allows me
to use HTML where I need more flexibility and still count on using widgets
where I can.
> Or, should I just dispense with the Form widget all together and simply
> create .KID files with my layouts.
Hmmm... It is another design choice... You can create .kid files and still
subclass some widget to use its methods.
--
Jorge Godoy <jgo...@gmail.com>
Right now this cannot be done, I think it should but just didn't get on
time ;)
This patch:
Index: turbogears/widgets/forms.py
===================================================================
--- turbogears/widgets/forms.py (revision 852)
+++ turbogears/widgets/forms.py (working copy)
@@ -541,6 +541,8 @@
d['hidden_fields'] = hidden_fields
d['submit'] = self.widgets['submit']
d["submit_text"] = d.get("submit_text", None)
+ d["field_for"] = self.field_for
+ d["error_for"] = lambda name: d["form_errors"].get(name)
return d
Should allow you to do something like this:
class MyForm(widgets.Form):
template = """
<form xmlns:py="http://purl.org/kid/ns#"
name="${name}"
py:attrs="form_attrs"
>
<table border="0">
<tr>
<td>${field_for("name").display()}</td>
<td>${field_for("age").display()}</td>
</tr>
<tr>
<td>${error_for("name")}</td>
<td>${error_for("age")}</td>
</tr>
</table>
</form>
"""
If you don't feel like patching you can achive the same thing by:
class MyForm(widgets.Form):
def update_data(self, d):
super(MyForm, slef).update_data(d)
d["field_for"] = self.field_for
d["error_for"] = lambda name: d["form_errors"].get(name)
and using this as a super class for any form you want to use field_for
and error_for in the template.
There's still work to do regarding the field label and help_text, but
should be a start. I think something on this line should be desirable
default behaviour and get into the trunk... Opinions?
Hope it helps, Alberto
Alberto
>Hi Keith,
>
>Right now this cannot be done, I think it should but just didn't get on
>time ;)
>
>This patch:
>
>
Aha. I was starting to look at someting like that and decided I was
missing something. I 'm really glad to see this patch both becuase it
lets me do what I want and it's confirmation that I really was beginning
to "get" the way widgets work.
I agree that something like this should be generally possible. In my
experience, form layout ("can you put this next to this...") is one of
the classic bike sheds in web development. It'll be nice to be able to
keep everthing associted with a form's structure encapsulated in one
place in my code...
Thanks for the quick responses...
Best,
Keith
IMHO putting "field_for" in the template scope of a form widget doesn't
make much sense since you can use it "only" if you know the form
structure (fields names) before doing the template and that's not the
use case of a form widget, OTOH I can't see any arm in putting it
there.
You can also do something like this if what you need is just
encapsulating the layout:
class FormFields(WidgetsDeclaration):
name = TextField()
age = TextField()
MyFormLayout(Widget):
template_vars = ['form']
template = """
<p py:content="form.field_for(name)"
"""
then:
form = Form(fields=FormFields())
form_layouted = MyFormLayout(form)
and use @validate(form).
Keep in mind that I haven't tested this.
Ciao
Michele
I think the patch can be included in the trunk. At least, I would make
use of this new feature.
Alberto