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@zope.org > http://mail.zope.org/mailman/listinfo/zope3-users > _______________________________________________ Zope3-users mailing list Zope3-users@zope.org http://mail.zope.org/mailman/listinfo/zope3-users