Skip to content

Big form widgets refactor to allow user-defined widgets, added number widgets#991

Merged
mdipierro merged 5 commits into
web2py:masterfrom
laundmo:refactor-widgets-formstyle
Aug 19, 2025
Merged

Big form widgets refactor to allow user-defined widgets, added number widgets#991
mdipierro merged 5 commits into
web2py:masterfrom
laundmo:refactor-widgets-formstyle

Conversation

@laundmo
Copy link
Copy Markdown
Contributor

@laundmo laundmo commented Aug 4, 2025

I was quite unsatisfied with the stats of FormStyleFactory and Form widgets. Especially when it comes to extending/overwriting them, the options were sparse - basically limited to overwriting them per field.

This PR is a pretty big refactor for Widgets and how they work.

  • Widgets themselves define what types they apply to, or even more complex matches if no direct type match was found.
  • Most Widgets should implement 1-2 methods now, one for an editable version and another for a readonly version
    • The readonly parameter of widget.make() wasn't used before, instead a default readonly formatting was applied to basically any field.
  • While Widget.make() still exists, its primarily called by form_html which is what creates the div/label structure used for comments, errors, etc. This allows user-defined widgets to change where in the HTML comments, errors, labels etc. appear.
  • The Widget class stores most of the context information and non-html widget structure, and updates it when necessary. Widget implementations call self.field, self.vars etc. when they need this information. This makes it far easier to work with custom logic compared to all of this logic being in FormStyleFactory.
  • I've tried to keep compatibility with the field.widget and formstyle.widgets options, which is done through implementing custom Widget subclasses to handle those.

Since this is a big and somewhat opinionated refactor, I haven't written documentation, exhaustive comments, and tests yet. Before I put that work in I'd want to know whether there's any chance this might be merged.

Comment thread py4web/utils/form.py Outdated
@laundmo
Copy link
Copy Markdown
Contributor Author

laundmo commented Aug 18, 2025

I've changed a few things.

  • theres no longer a mandatory class var type_name which is used as a shortcut. Instead, widgets are stored as a list which is looped in reverse order until a matching widget is found. This makes it far more flexible to overwrite default widgets conditionally (if a field is of type string and has a specific validator, for example)
  • Fixed the widget which is used for compatibility with the previous widget system, to actually call them properly with widget.make(self, field, value, error, title, placeholder="", readonly=False
  • documented most things, including the breaking change from passing instances (formstyle.widgets["fieldname"] = Widget()) to passing classes (formstyle.widgets["fieldname"] = Widget)

@mdipierro mdipierro merged commit b2e7174 into web2py:master Aug 19, 2025
5 checks passed
@mdipierro
Copy link
Copy Markdown
Contributor

Nice work!

@laundmo laundmo deleted the refactor-widgets-formstyle branch August 29, 2025 12:20
mdipierro added a commit that referenced this pull request Sep 22, 2025
laundmo added a commit to laundmo/py4web that referenced this pull request Sep 22, 2025
mdipierro pushed a commit that referenced this pull request Oct 19, 2025
…ed number widgets (#991)" (#1001)

* Reapply "Big form widgets refactor to allow user-defined widgets, added number widgets (#991)"
This reverts commit a1f6238.
* fix: add forgotten instantiation of new-style widgets
* Clarify in docs that FormStyleDefault should be cloned before modifying
* add tests for FormStyle.widgets backwards compat, and fix discovered issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants