![]() |
|
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.
What is worth noting in the snippet below is the usage of the 'onchange'=> remote_function( ... you can use the remote_function in many places to call other functions ... like in the "update", "complete" etc...
<div id="js_updating">Stand by..</div> <?php echo form_tag('/module/action', 'method=get class=simpleForm') ?> Please select the day: <?php echo input_date_tag('day', 'now', array('rich' => true, 'readonly'=>true, 'onchange'=> remote_function( array( 'update' => 'Area To Update (DIV TAG)', 'url' => 'MODULE/ACTION', 'loading' => "Element.show('js_updating')", 'complete' => "Element.hide('js_updating')" )))); ?> </form>