Question

I'm using Plone with dexterity and I'm validating 2 related fields using the invariant decorator. Everything works but... I'd like to move the generic error message on one specific field.

How can I do this? I've found a three years old suggestion by Martin Aspeli about how it would be cool doing it:

http://plone.293351.n2.nabble.com/plone-app-form-does-not-display-invariant-errors-td348710.html

but they dont came out with a solution.

I've also found a way to do it but it's ugly: placing on the update method of the form this code:

for widget in widgets:
    name = widget.context.getName()
    if errors:
        for error in errors:
            if isinstance(error, Invalid) and name in error.args[1:]:
                if widget._error is None:
                    widget._error = error

Isn't there a lower level implementation that allows to pass the names of the fields to the raised Invalid and does not need to loop trough all the fields and all the errors for each field?!?

Was it helpful?

Solution

You can do this by doing your extra validation in the form's action handler, and raise WidgetActionExecutionError specifying the widget for which the error should be shown.

This looks as follows (taken from http://plone.org/products/dexterity/documentation/manual/schema-driven-forms/customising-form-behaviour/validation):

from five import grok
from plone.directives import form

from zope.interface import invariant, Invalid
from zope import schema

from z3c.form import button
from z3c.form.interfaces import ActionExecutionError, WidgetActionExecutionError

from Products.CMFCore.interfaces import ISiteRoot
from Products.statusmessages.interfaces import IStatusMessage

from example.dexterityforms.interfaces import MessageFactory as _


...


class OrderForm(form.SchemaForm):

    ...

    @button.buttonAndHandler(_(u'Order'))
    def handleApply(self, action):
        data, errors = self.extractData()

        # Some additional validation
        if 'address1' in data and 'address2' in data:

            if len(data['address1']) < 2 and len(data['address2']) < 2:
                raise ActionExecutionError(Invalid(_(u"Please provide a valid address")))
            elif len(data['address1']) < 2 and len(data['address2']) > 10:
                raise WidgetActionExecutionError('address2', Invalid(u"Please put the main part of the address in the first field"))

        if errors:
            self.status = self.formErrorsMessage
            return

I think it may also be possible to raise WidgetActionExecutionError from your invariant, but then it might not do what you want if the invariant is getting checked at some other time than while processing a z3c.form form.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top