How do I avoid automatic submit on pressing Enter?

(Part of ZopeInAnger)

Formlib uses an action sequence to validate data. This action sequence is invoked by form.handleSubmit when it is invoked when a form is updated, as described in zope/formlib/form.txt. By defining action buttons like:

<div metal:define-macro="entryform_actionbuttons">
  <div id="actionsView" class="actionsbuttons">
    <span class="actionButtons"
        tal:condition="view/availableActions">
      <input tal:repeat="action view/actions"
           tal:replace="structure action/render"
      />
    </span>
  </div>
</div>

a submit button gets generated, which validates through:

errors, action = form.handleSubmit(self.actions, data, self.validate)

So you define the form buttons, including a submit button. This submit button reacts on hitting ENTER in a form - by submitting the page. This is default browser behaviour.

There are two ways to stop this behaviour. The first one is to intercept ENTER with Javascript by defining an onSubmitForm routing. But this does not always work. And there is no standard mechanism.

The other is not to use a submit button on a form at all, but another button type. This is used by most web development tools. It is not clear to me what the elegant route is with formlib as (1) the submit button is autogenerated and (2) the validation scheme depends on a SUBMIT parameter - so it needs to be there.

Anyone a way of handling this properly?

I am less worried about it submitting on enter than I am it appearing to submit, but not really save. I don't imagine you can prevent browser behavior on the server side. At best you can probably set:

self.status = _("Please use a button to submit the form")

We used this monkey patch to catch and ACTUALLY submit the POST.:

from zope.formlib
class MyAction(form.Action):
    """A monkey patch to catch submissions made by pressing return instead of clicking a button."""
    def submitted(self):
        """Set the form action if there isn't one and the the request method is POST"""
        if self.form.request.environ['REQUEST_METHOD'] == 'POST'\
               and not [k for k in self.form.request.form if k.startswith('form.actions.')] :
            self.form.request.form[u'form.actions.save'] = u'Save'
        return (self.__name__ in self.form.request.form) and self.available()
form.Action = MyAction

I don't know if it is naive and will break something deeper. If so it was my idea, if it works correctly it was Chris Shenton's.

Really though it seems to work with a Cancel and Save button as well as simply typing return.



( 97 subscribers )