[Zope3-Users] MultiWidget

Roger Ineichen dev at projekt01.ch
Sun Jan 18 23:04:56 EST 2009


Hi Christian

> Betreff: [Zope3-Users] MultiWidget
> 
> Hi,
> 
> the new MultiWidget in z3c.form is great! I like the way 
> input errors are reported. Thank you for this!
> 
> To help the users of my app a little I was thinking about 
> conditions for the the add and remove buttons. I think the 
> old tuple-sequence widget in zope.app.form had such a 
> feature.  I want the add button to appear only if the number 
> of subwidgets is below the max_length in the schema. And the 
> remove button (and even the select boxes) should only appear 
> if the number of subwidgets exceeds the min_length of the 
> schema or zero. -- Well, OK, one might run into an inregular 
> state when selecting several widgets for removal so that the 
> min_length is violated. But, at least there should not be a 
> remove button if the number of subwidgets equals zero, and no 
> add button should appear if the number of subwidgets equals 
> (or exceeds) max_length.
> 
> To achive this I started with conditions for the buttons. But 
> the problem is that the button conditions are checked very 
> early during the setup of the widget when one can't yet get 
> the number of subwidgets form '_value'-attribute or 
> 'widgets'-attribute of the MultiWidget instance.
> So the more general question is: How would one check button 
> conditions that depend on a widget's state (number of 
> subwidgets, values...)?
> 
> Do you have you a hint for me?

Try to call updateActions *again* after action.execute get called.

def update(self):
    self.updateWidgets()
    self.updateActions()
    self.actions.execute()
    # update action conditions they get probably changed by execute
    self.updateActions()

btw, I will review the form update part again because
I think we need more hooks if it comes to update widgets,
actions and conditions.

I think your usecase is very good starting point for take
another look at this part.

Probably a possible new hooks could be updateActionCondition()
which get called after action.execute()

Regards
Roger Ineichen
_____________________________
END OF MESSAGE


> I code I was trying:
> 
> import zope.interface
> from z3c.form import widget, button, interfaces from 
> z3c.form.browser import multi from zope.i18n import translate 
> import zope.i18nmessageid
> 
> _ = zope.i18nmessageid.MessageFactory("zope")
> 
> 
> class MultiWidget(multi.MultiWidget):
> 
>     buttons = button.Buttons() # reset buttons
> 
>     showLabel = False
> 
>     def addButtonLabel(self):
>         button_label = _('Add %s')
>         button_label = translate(button_label, context=self.request,
>                                  default=button_label)
>         title = getattr(self.field.value_type, 'title', _(u"an item"))
>         title = translate(title, context=self.request)
>         return button_label % title
> 
>     @button.buttonAndHandler(_(u"Add an item"),
>                              name = "add",
>                              condition = lambda form: form.needAdd(),
>                              )
>     def handleAdd(self, action):
>         self.appendAddingWidget()
> 
>     def needAdd(self):
>         # TODO: this gets called before the widgets are updated and we
>         # still have self._value == []. So always True is returned
>         max_length = getattr(self.field.value_type, 
> 'max_lenght', None)
>         if max_length is None:
>             return True
>         else:
>             return len(self._value) < max_length
> 
>     @button.buttonAndHandler(_("remove-selected-items",
>                                u"Remove selected items"),
>                              name = "remove",
>                              condition = lambda form: 
> form.needRemove(),
>                              )
>     def handleRemove(self, action):
>         """see z3c.form.browser.multi.MultiWidget.handleRemove()"""
>         self.widgets = [widget for widget in self.widgets
>                         if ('%s.remove' % (widget.name)) not 
> in self.request]
>         self.value = [widget.value for widget in self.widgets]
> 
>     def needRemove(self):
>         # TODO: This gets called before the widgets are updated and
>         # len(self._value) == 0.
>         min_length = getattr(self.field.value_type, 'min_length', 0)
>         return len(self._value) > min_length
> 
>     def updateActions(self):
>         """Use as a hook to make a nice add button label."""
>         self.buttons['add'].title = self.addButtonLabel()
>         super(MultiWidget, self).updateActions()
> 
> 
> @zope.interface.implementer(interfaces.IFieldWidget)
> def multiFieldWidgetFactory(field, request):
>     return widget.FieldWidget(field, MultiWidget(request))
> 
> 
> @zope.interface.implementer (interfaces.IFieldWidget) def 
> MultiFieldWidget(field, value_type, request):
>     return multiFieldWidgetFactory(field, request)
> 
> 
> Regards,
> Christian
> _______________________________________________
> Zope3-users mailing list
> Zope3-users at zope.org
> http://mail.zope.org/mailman/listinfo/zope3-users
> 



More information about the Zope3-users mailing list