mercredi 6 octobre 2010

[SYMFONY][JQuery] Gérer ses formulaires en Ajax, validation soumission, etc !

Bonjour,

Bonne nouvelle : Cet article est très utile :)
Il va nous permettre de traiter un formulaire à la volée et de récupérer les erreurs qu'un mauvais remplissage pourrait renvoyer.

Imaginons que l'on veuille ajouter un commentaire à un article de blog.
On affiche notre article puis en dessous, on affiche un lien pour commenter l'article.
Le formulaire de commentaire doit connaitre implicitement le sujet à commenter.
Aussi, il faudra :

1. modifier le formulaire de commentaire pour passer l'id de l'article en douce (grâce au widget sfWidgetFormInputHidden

/lib/form/Doctrine/CommentForm.php
public function configure()
  {
      $this->widgetSchema['model'] = new sfWidgetFormInputHidden();

      $this->getWidgetSchema()->setLabels(array(
          'author'=> "Pseudo :",
          'content'=> "Message :",
          ));
  }
 2. passer l'id de l'article lorsqu'on charge le formulaire
On peut soit afficher le formulaire dès le chargement de la page, soit en Ajax, faisons le en Ajax, ce serait trop facile ;)

On va donc utiliser JQuery. Installons déjà le plugin sfJqueryReloadedPlugin
Une fois que c'est fait et que l'on a bien inclut le helper jQuery, on peut se créer dans un fichier js que l'on va inclure (je vous fait confiance là dessus) une fonction qui sera déclenchée lors du clic sur le bouton commenter.

/app/frontend/blog/show/myArticle

<div>
    <h1>
        <?php echo $article->getTitle(); ?>
    </h1>
    <p><?php echo $article->getContent(); ?></p>
</div>
<input type="button" value="Commenter" onclick="comment(<?php echo $article->getId(); ?>)"/> 
<div id="commentForm"></div>

/web/js/main.js

function comment(arg){
    $.post("/comment/new",
    {id: arg},
    function(data)
    {
        $("#commentForm").html(data);
        $("#commentForm").slideToggle();
    });
}
Jusque là, on est pas trop désorienté, c'est juste la facon de charger le formulaire de commentaire.
Il faut donc maintenant créer l'action comment dans le module blog :

/app/frontend/modules/comment/actions/actions.php

public function executeComment(sfWebRequest $request) {
        $comment = new Comment();
        $comment->setArticleId($request->getParameter("id"));
        $this->form = new CommentForm($comment);
    }
Vous l'avez surement compris, dans le code précédent, on créé un objet commentaire pour pré-remplir avec l'id de l'article.  On charge ensuite commentSuccess.php. Crééz le comme vous voulez, je vais personnelement aller au plus simple pour bien montrer la facilité du processus.


/app/frontend/modules/comment/templates/newSuccess.php

<?php use_helper('jQuery'); ?>
<?php echo jq_form_remote_tag(array(
    'update'   => 'commentForm', /* représente l'id de la div que l'on doit mettre à jour */
    'url'      => 'comment/'.($form->getObject()->isNew() ? 'create' : 'update'),
)); ?>
  <?php echo $form; ?>
<input type="submit" value="Commenter"/>
</form>
On réinclut le helper de jQuery. Pourquoi ? car sinon, la vue, isolée car chargée en ajax est incapable de trouver la fonction jq_form_remote_tag.
On passe 2 paramètre à cette fonction : url, qui désigne l'action que va éffectuer le formulaire et update qui définit dans quel id de la page l'action ajax va afficher la réponse. Içi, dans la div d'id commentForm.

Désormais, il faut dire quel vue on va afficher lorsque cela sera validé. Le formulaire, une fois validé et enregistré raffiche le formulaire pour l'éditer, fonctionnement par défaut mais qui ne nous convient pas. On peut pour changer cela en ajoutant un test dans la template newSuccess.php.
Grâce à l'attribut $form->getObject()->isNew() des formulaires, on peut en déduire le comportement que l'on doit adopter, soit afficher le formulaire (comportement 1) soit afficher le commentaire (comportement 2).


/app/frontend/modules/comment/templates/newSuccess.php

<?php if($form->getObject()->isNew()){?>
    
        <h3><?php echo __("Ajout d'un commentaire :");?></h3>
        <?php include_partial('form', array('form' => $form)) ?>
    
<?php }else{
    include_partial("show",array("comment"=>$comment));
}?>



Voilà qui est fait. Maintenant. Le formulaire est en Ajax, s'il y a des erreurs dans le remplissage du formulaire, les erreurs seront affichées puis lorsque cela sera valide, le nouveau commentaire sera affiché comme les autres commentaires grâce au fichier _show.php que vous aurez créé selon votre envie de mise en forme des commentaires.

2 commentaires:

  1. Salut Leny,

    Je vois que contrairement à moi tu maîtrise parfaitement l'Ajax dans symfony.

    J'essaye de mettre en place une système de vote j'aime /j'aime pas tout con sur mon site.

    Je voudrais juste qu'au click du bouton de vote le nombre de vote se mette à jour en ajax.

    Pourrais-tu me donner un coup de main ?

    Dans mon index:

    1.J'ai mon bouton image et un partial :
    < img class='like' ...>


    2.dans mon partial j'ai juste un compteur :
    '.$compteur_like..../p>'; ?>

    3.En jquery je lance l'action Ajax au click :
    jQuery('img.like').click(function(){
    jQuery.ajax({
    type: "GET",
    url: jQuery('#hiddenRoute').attr('value')
    });
    });

    4.l'action (hiddenRoute) est lancée et effectue les taches en bdd :

    //on incremente le compteur
    Doctrine::getTable('Accueil')->incrementCompteur();
    //on récupère la nouvelle valeur du compteur
    $obj = Doctrine_Query::create()
    ->from('Accueil a')
    ->fetchOne();
    //puis on retourne le partial
    return $this->renderPartial('ip/vote', array('compteur' => $obj->compteur_like));

    L'appel Ajax s'effectue bien et je peux voir le contenu de mon partial dans la console de firebug ! Mais mon partial ne se met pas à jour.

    Vois tu l'erreur ?? Je désespère la ...

    Merci par avance.

    RépondreSupprimer
  2. Salut Maka,
    Merci de lire mon blog (même s'il s'agit de mon ancien, le nouveau se trouve ici : www.leny-bernard.com

    Je viens d'etre papa depuis avant hier donc je ne peux pas tellement regarder et tester ton code, cependant je vois clairement une erreur, l'appel ajax fait par ton script jQuery a l'air de fonctionner, cependant, tu ne lui dit pas ce qu'il doit faire de ce qu'il recoit. Je pense que si tu installe firebug dans firefox et que tu regarde ce que tu recois dans la console, si ton code est correct au niveau de ton controlleur(action), tu devrais voir la vue partielle (partial). Donc ton problème semble être du au fait qu'il faut que tu donne à ta fonction le callback qui va afficher ta réponse.


    Voici donc comment je ferais (à prendre avec précautions, je fais ça de tête sans tester quoi que ce soit et sans avoir très bien dormis les nuits dernières :) :

    $.post($('#hiddenRoute').val(),
    {/*PUT HERE YOUR PARAMS LIKE THAT! name:value*/},
    function(response)
    {
    $("#where to put the partial").html(data);
    });

    Si ca ne marche pas, reviens vers moi dans 1 ou 2 jours, bon courage.

    RépondreSupprimer

Bonjour,