Want to use 2 or more buttons in a html form, but you're having trouble knowing which button you clicked to submit the form, when it's time to validate it? If you're using Zend Form, there's a very simple way to know. Recently, in a project, I came across just this type of situation.
Let me describe said situation for you; The user has a list of items and they've chosen to delete one. Given such a volatile action, you want them to doubly opt-in and confirm that they want to do this.
The last thing you want your user to feel, after they've clicked the delete link, is "NO WAAAAAAIIIIT! I didn't mean to do that". So the user clicks &'delete&' and is directed to a confirmation page (which is rendered with Zend Form). There are two buttons on the page; the first is "Delete Item", the second "Cancel".
If the user clicks either button, the form submits to itself, where the value of the button clicked is determined. If the user clicks "Delete Item", then the deletion is carried out, deleting the item from the datasource. If the user clicks "Cancel" the user is returned to the list of items they were previously viewing, the item is not deleted and the user is provided a message, confirming the non-deletion.
How do you do it?
But how do you determine which button was clicked by the user. Up until now, I've been using the getValues() or getValue() method on Zend_Form for retrieving form input. However, regardless of whether setIgnore is true or false on a form element, it's not contained in that array. So how do you determine which button was clicked.
Well, there's another set of methods available in Zend_Form; these are getUnfilteredValue() and getUnfilteredValues(). These do include the value of the form buttons. The value returned is the value property of the button, if it's clicked or NULL if it wasn't. Now what could be simpler? Not much to be honest. But what would a good post be without a working example? Not much either.
The Working Example
Ok now, have a look at the code below (sorry about the image instead of inline code - WordPress is playing up a bit at the moment). In it you see a simple controller action, which is aimed to delete some content. It does a standard check of whether the request was a POST or not and either displays the form, or attempts to validate the rendered content. No surprises here.
Then, if the form is a POST submission and the form is valid, I leave the validation requirements up to your hearts desire, we retrieve the value of the submit and cancel buttons, unimaginatively called &'submit&' and &'cancel&'.
If the button is clicked, it will have a value, if not, it will be null. So, then we check if the submit button was clicked. If so, the user has confirmed the intent to delete the item, so we do that. If not, we then use the redirector action helper to redirect back to where we were - in this case, viewing a list of the existing items. I won't get in to a discussion of redirect versus _forward. That's already been done. But _redirector's ***better!***
Is that it?
Like all things in software, there's many ways to accomplish them. But this one is simple and effective. However, there's a number of ways to improve on this. Here's a suggestion of the first three that come to mind:
- A simple function could be put in the controller to return the value of the button clicked
- You could handle it in a preDispatch of the controller
- You could dynamically change the form action with jQuery (scriptaculous, mootools etc)
What do you think? Where can it be improved? What would you do differently?