![]() |
|
Snippets |
|
The example is for a blog. The page that displays a post also proposes an AJAX form to add a comment. We want that when the validation of this form fails, it displays again in the page with an error message, and when the validation succeeds, the form is replaced byu the comment just posted.
The idea is to take advantage of the way the update option of the form_remote_tag() helper works. It accepts an associative array, where you can specify different zones to update in case of success and failure. The only problem is that for Prototype, a failure is a return code other than 2XX. So when we return the form showing the error message again, we need to set the status code to 404, for instance, for Prototype to choose to update the correct zone.
That, plus the usual use of partials here and there, and you have a working solution:
in modules/post/actions/action.class.php
// Display the form public function executeShow() { $this->post = PostPeer::retrieveByPk($this->getRequestParameter('post_id')); }
in modules/post/templates/showSuccess.php
// Display question detail here ... // Beginning of Comment zone <div id="added_comment" style="display_none"> </div> <div id="add_comment"> <?php include_partial('comment/add_comment', array('post' => $post)) ?> </div>
in modules/comment/templates/_add_comment.php
<?php use_helper('Javascript', 'Validation') ?> <?php echo form_remote_tag(array( 'url' => 'comment/add', 'update' => array('success' => 'added_comment', 'failure' => 'add_comment'), 'script' => true, 'loading' => "Element.show('indicator')", 'success' => "Element.hide('indicator');Element.show('added_comment');Element.hide('add_comment');", 'failure' => "Element.hide('indicator');", )) ?> <?php echo input_hidden_tag('post_id', $post->getId()) ?> <?php echo form_error('body') ?> <label for="body">Your comment</label> <?php echo textarea_tag('body') ?> <?php echo submit_tag('Send') ?> </form>
in modules/comment/validate/add.yml
methods: post: [body] fillin: activate: Yes names: body: required: Yes required_msg: You must provide a comment validators: spamValidator spamValidator: class: sfRegexValidator param: match: No pattern: /http.*http/ match_error: Do not provide more than one URL - It is considered Spam
in modules/comment/actions/action.class.php
public function handleErrorAdd() { $this->post = PostPeer::retrieveByPk($this->getRequestParameter('post_id')); $this->getResponse()->setStatusCode(404); return sfView::ERROR; } public function executeAdd() { $post = PostPeer::retrieveByPk($this->getRequestParameter('post_id')); $this->forward404Unless($post); $comment = new Comment(); $comment->setPost($post); $comment->setAuthor($this->getUser()->getAuthor()); $comment->setBody($this->getRequestParameter('body')); $comment->save(); $this->comment = $comment; }
in modules/comment/templates/addError.php
<?php include_partial('comment/add_comment', array('post' => $post)) ?>
in modules/comment/templates/addSuccess.php
Your comment has been added: <div class="comment"> <?php echo $comment->getBody() ?> </div>
As a bonus, the form is still there after a successful submission (but hidden), so with a few more lines of code, you can still provide a Digg-like "edit comment for the next 60 seconds" feature.
Comments on this snippet
I did everything like in the snippet, but the comment form will not be hidden, if the action was successful. Any ideas, why this happens? There are no javascript errors on my page.
Okok, i found my mistake. I forgot to include the indicator element and so nothing at all happend after the successful action.
I think it's better to let the added comment appear 'after' the last comment in the current list, and not display it in a custom layer. Just a suggestion ;)
Don't forget to remove any global layout in the addError and addSuccess ( the resulting success/error templates corresponding to the url parameter in form_remote_tag())templates to prevent loading the layout content twice into each other.
In the view.yml of the module or app: addSuccess: has_layout: no
addError: has_layout: no
Thanks for this code. I used it for my stuff and did some modifications. I didn't want to redisplay the form but keep it on screen and just get the error messages. To do this I only get the form errors in the Error action. To do this I wrote a small helper that creates JS code on the fly and display the errors for the fields having issues and hiding the ones for which there is no problem.
For example, in my actionError.php I have
<?php use_helper('jsErrorDisplay'); js_error_display($sf_request); ?> <div class="form_incomplete"> Please verify your information. </div>
My helper is
function js_error_display($request) {
}
Thanks
Hi, I want a mixed behaviour of that. I mean, when there's an error I want the form in the screen and also the validation error messages. I have added this code at the begining of the form partial file.
<?php if ($sf_request->hasErrors()): ?>
<div id="errors" style="padding:10px;"> Errores: <ul> <?php foreach ($sf_request->getErrors() as $error): ?> <li><?php echo $error ?></li> <?php endforeach; ?> </ul> </div> <?php endif; ?>
The thing is that the validation is done, no submit is done but I can't see the errors on the screen. Any useful tip?
Thanks in advance.