Page 1 sur 6

Afficher les résultats d'une recherche sans recharger la pag

Posté : 02 juil. 2007, 11:43
par béka
Bonjour tout le monde, je souhaiterais qu'n utilisateur fasse une recherche à partir de différents critères qui lui sont proposés à travers des checkbox. Lorsqu'il valide sa recherche, je souhaiterais que le résultat s'affiche en bas des checkbox mais sans recharcger la page.

Pour ça, j'ai pensé utiliser AJAX, mais je ne vois pas comment faire. Quel code et où placer mon code.

Voilà déjà le code que j'ai fait :
<?
echo "<br /><br />Choose the different criteria which correspond to your request : ";
/*---------------------------------*/
//on ouvre le fichier criteria.xml
$criteriaFile = $cfg['ressources_root'].'criteria.xml';
$domCriteria = new DOMDocument('1.0','UTF-8');
$domCriteria->load($criteriaFile);
$xpCriteria = new DOMXPath($domCriteria);
$cat_criteria = $domCriteria->getElementsByTagName('cat');
$result_find_criteria = $domCriteria->getElementsByTagName('criteria');?>

<form name="critera" method="post" action="search-engine.php"><?
echo "<ul>";
foreach($cat_criteria as $cat){
  $name_cat = $cat->getAttribute('name');
  $id_cat = $cat->getAttribute('id');
  echo "<br /><input type=\"checkbox\" name=\"cat\" value=\"$id_cat\">".$name_cat."</input>";
  foreach ($cat->childNodes as $criteria)
  {
    if ($criteria->nodeType != XML_ELEMENT_NODE) continue;
    if ($criteria->tagName == 'criteria')
    {
      $name_criteria = $criteria->getAttribute('name');
      $id_criteria = $criteria->getAttribute('id');      
      echo "<ul><input type=\"checkbox\" name=\"crit\" value=\"$id_criteria\">$name_criteria</input></ul>";
    }
  }
}
echo "</ul>";?>
<input type="submit" value="Search" />
</form>
<?
/*-----------------------------------------------------*/
//on affiche le résultat en fonction d'un seul critère //
/*-----------------------------------------------------*/

$link_file = $cfg['ressources_root'].'/matrix/criteria-practice.xml';

//simple xml va convertir ce fichier xml en tableau
//Chaque type de balise enfant de la racine est une propriété qui est un tableau indexé numériquement et chaque index est un nouvel objet SimpleXML.
$xml = simplexml_load_file($link_file);

if ( $_POST['cat'] or $_POST['crit'] ){
foreach($xml->link as $value) {//tableau qu'on parcours. Chaque valeur est un objet simpleXML
   if($value->criteria[0]['idcat']==$_POST['cat'] or $value->criteria[0]['idcrit']==$_POST['crit']) {
   //Il s'agit de récupérer la valeur de l'attribut 'idcat' du noeud 'criteria' de la balise 'link' analysée - pareil pour 'idcrit'
      $practice[]=( (int)$value->practice[0]['id'] );
      $id_practice = $practice[0];
   }
}

//on ouvre le document xml qui correspond à la recherche
$practiceFile = $cfg['ressources_root'].'content/practice/'.$id_practice.'.xml';
$domPractice = new DOMDocument('1.0','UTF-8');
$domPractice->load($practiceFile);
$xpPractice = new DOMXPath($domPractice);
$item_practice = $domPractice->getElementsByTagName('item');


if (isset($item_practice)){
  foreach ($item_practice as $item) {
    foreach ($item->childNodes as $child){
      if($child->nodeType != XML_ELEMENT_NODE) continue;
      if($child->tagName == 'title'){
        $titre = utf8_decode($child->firstChild->nodeValue);}
      elseif($child->tagName == 'short_description'){
        $short_description = utf8_decode($child->firstChild->nodeValue);}
    }
  echo "<p>$titre<br/>$short_description";
  }
}
else {
  echo "pas de practice";
  }
}
?>

Posté : 02 juil. 2007, 13:29
par sadeq
Hé bien, si tu veux utiliser Ajax, il faut diviser le script que t'as donné en deux:
1. le formulaire dans un script avec le module Ajax et les évènements déclencheurs.
2. la recherche et l'affichage dans un autre script qui sera appelé par Ajax

Rappel du principe Ajax:

Ajax est un moteur javascript basé sur l'objet HTTPRequest qui appelle un script serveur et en reçoit une réponse XML/HTML pour la placer dans un conteneur HTML dans la page HTML chargée.

Le script serveur appelé par Ajax peut être alors un programme PHP qui envoit des echos (affichage) de texte/XML/HTML/JS.

Pour utiliser d'Ajax il faut :
  • D'abord prévoir des balises conteneurs telque <div>, <span>, <textArea>, ... et leur donner des id.
    Programmer une fonction Ajax qui doit être déclenchée pour appeler le script serveur adéquat et récupèrer sa réponse pour la placer dans le conteneur adéquat
    En suite, il faut programmer des évènements javascript telque onChange, onClick, ... sur des objets qui doivent déclencher le traitement Ajax.
Exemple:
Page: Ajax_dit_bonjour.html
<script>
          /** 
         * Moteur Ajax 
         */ 	  
		 function getXhr(){ 
            var xhr = null; 
            if(window.XMLHttpRequest) // Firefox et autres 
               xhr = new XMLHttpRequest(); 
            else if(window.ActiveXObject){ // Internet Explorer 
               try { 
                         xhr = new ActiveXObject("Msxml2.XMLHTTP"); 
                     } catch (e) { 
                         xhr = new ActiveXObject("Microsoft.XMLHTTP"); 
                     } 
            } 
            else { // XMLHttpRequest non supporté par le navigateur 
               alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest..."); 
               xhr = false; 
            } 
          return xhr; 
         } 
          
          /** 
         * Méthode qui appelle un script serveur et renvoit sa réponse
         * 
		 * serveur: l'url du script serveur appelé
		 * reponse: objet HTML donné par référence à un conteneur HTML de la page chargée
		 * paramètres: liste des paramètre éventuellement passés au script serveur (param1=valeur1&param2=valeur2...)
		 */
         function getByAjax(serveur, reponse, paramètres){ 
           var xhr = getXhr(); //Nouvelle instance Ajax
           if (xhr && serveur){
		    // On défini la fonction observant la communication Ajax/serveur 
            xhr.onreadystatechange = function(){ 
               // le code 4/200: détermine que Ajax a reçu une réponse du serveur 
               if(xhr.readyState == 4 && xhr.status == 200){ 
                  reponse.innerHTML = xhr.responseText;  //renvoit la réponse du serveur dans le conteneur reponse
               } 
            } 

            // Déclenchement de l'appel Ajax/serveur (avec passage de paramètres en POST)
            xhr.open("POST" ,serveur ,true); 
            xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); 
            xhr.send(paramètres); 
		   }
        }
</script>

<!-- Test de la communication Ajax -->
<p>Déclencheur <button onClick="getByAjax('bonjour.php', document.getElementById('afficheur'), null);">Dit Bonjour!</button></p>
<p>Récepteur Ajax <div id="afficheur"></div></p>
Page: bonjour.php
<?php
echo "Bonjour! dit Ajax.";
?>

Posté : 02 juil. 2007, 14:25
par béka
Donc voilà, j'ai adapté ton code pour mes besoins.

Peux tu me die où il y a des erreurs. En effet, il y en a car la requete (je suppose que ca s'appelle ainsi) a le status Loading... et pendant très longtemps.
Voici mes codes. Je pense que le soucis vient du passage de mes paramètres. En effet, dans l'appelle de la fonction, j'ai null au lieu des paramètres, mais comment passer ceux-ci ?

page search-engine.php :
<script>
          /** 
         * Moteur Ajax 
         */       
         function getXhr(){ 
            var xhr = null; 
            if(window.XMLHttpRequest) // Firefox et autres 
               xhr = new XMLHttpRequest(); 
            else if(window.ActiveXObject){ // Internet Explorer 
               try { 
                         xhr = new ActiveXObject("Msxml2.XMLHTTP"); 
                     } catch (e) { 
                         xhr = new ActiveXObject("Microsoft.XMLHTTP"); 
                     } 
            } 
            else { // XMLHttpRequest non supporté par le navigateur 
               alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest..."); 
               xhr = false; 
            } 
          return xhr; 
         } 
          
          /** 
         * Méthode qui appelle un script serveur et renvoit sa réponse
         * 
         * serveur: l'url du script serveur appelé
         * reponse: objet HTML donné par référence à un conteneur HTML de la page chargée
         * paramètres: liste des paramètres éventuellement passés au script serveur (param1=valeur1&param2=valeur2...)
         */
         function getByAjax(serveur, reponse, parametres){ 
           var xhr = getXhr(); //Nouvelle instance Ajax
           if (xhr && serveur){
            // On défini la fonction observant la communication Ajax/serveur 
            xhr.onreadystatechange = function(){ 
               // le code 4/200: détermine que Ajax a reçu une réponse du serveur 
               if(xhr.readyState == 4 && xhr.status == 200){ 
                  reponse.innerHTML = xhr.responseText;  //renvoit la réponse du serveur dans le conteneur reponse
               } 
            } 

            // Déclenchement de l'appel Ajax/serveur (avec passage de paramètres en POST)
            xhr.open("POST" ,serveur ,true); 
            xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); 
            xhr.send(parametres); 
           }
        }
</script>

<?
include('html_head.php');
include('header.php');
?>
<div id="content">
<?
echo "<br /><br />Choose the different criteria which correspond to your request : ";
/*---------------------------------*/
//on ouvre le fichier criteria.xml
$criteriaFile = $cfg['ressources_root'].'criteria.xml';
$domCriteria = new DOMDocument('1.0','UTF-8');
$domCriteria->load($criteriaFile);
$xpCriteria = new DOMXPath($domCriteria);
$cat_criteria = $domCriteria->getElementsByTagName('cat');
$result_find_criteria = $domCriteria->getElementsByTagName('criteria');?>


<script type="text/javascript"> 

</script>

<form name="critera" method="POST" action="search-engine.php"><?
echo "<table align='center'><tr><ul>";
foreach($cat_criteria as $cat){
  $name_cat = $cat->getAttribute('name');
  $id_cat = $cat->getAttribute('id');
  echo "<td valign='top'><br /><input type=\"checkbox\" id=\"cat\" name=\"cat\" value=\"$id_cat\"><strong>".$name_cat."</strong></input>";
  foreach ($cat->childNodes as $criteria)
  {
    if ($criteria->nodeType != XML_ELEMENT_NODE) continue;
    if ($criteria->tagName == 'criteria')
    {
      $name_criteria = $criteria->getAttribute('name');
      $id_criteria = $criteria->getAttribute('id');      
      echo "<ul><input type='checkbox' id='crit' name='crit' value='$id_criteria'>$name_criteria</input></ul>";
    }
  }
}
echo "</ul></tr></table>";?>
</form>

<button onClick="getByAjax('result_request.php', document.getElementById('ajax'), null);">Search</button>
<div id="ajax"></div>
page result_request.php :
<?
/*-----------------------------------------------------*/
//on affiche le résultat en fonction d'un seul critère //
/*-----------------------------------------------------*/

$link_file = $cfg['ressources_root'].'/matrix/criteria-practice.xml';
$xml = simplexml_load_file($link_file);//on ouvre le fichier xml

//on vérifie l'existence des varaibles passées par le formulaire si elles n'existent pas, on meur affecte une valeur vide
if (!isset($_POST['cat'])) { $_POST['cat'] = ''; }
if (!isset($_POST['crit'])) { $_POST['crit'] = ''; }

//si les variables ne sont pas vides
if ( ($_POST['cat'] != '') or ($_POST['crit'] != '') )
{
  foreach($xml->link as $value)
  {
     if( $value->criteria[0]['idcat']==$_POST['cat'] or $value->criteria[0]['idcrit']==$_POST['crit'] )
     {
        $practice[]=( (int)$value->practice[0]['id'] );
        if (isset($practice[0]))
        {
          $id_practice = $practice[0];
        }
        else $id_practice = '';
     }
  }
  if ( (isset($id_practice)) and ($id_practice != '') ) // si $id_practice n'est pas vide
  { 
    //on ouvre le document xml qui correspond à la recherche
    $practiceFile = $cfg['ressources_root'].'content/practice/'.$id_practice.'.xml';
    $domPractice = new DOMDocument('1.0','UTF-8');
    $domPractice->load($practiceFile);
    $xpPractice = new DOMXPath($domPractice);
    $item_practice = $domPractice->getElementsByTagName('item');


    foreach ($item_practice as $item) 
    {
      foreach ($item->childNodes as $child)
      {
        if($child->nodeType != XML_ELEMENT_NODE) continue;
        if($child->tagName == 'title')
        {
          $titre = utf8_decode($child->firstChild->nodeValue);
        }
        elseif ($child->tagName == 'short_description')
        {
          $short_description = utf8_decode($child->firstChild->nodeValue);
        }
      }
      $msg = "<p>$titre<br/>$short_description</p>";
    }
  }
  else
  { 
    $msg = "<p>There is no practice which corresponds to your request. Please refine your search</p>";
  }
  echo $msg;
}
?>

Posté : 02 juil. 2007, 14:43
par sadeq
Dans ton cas t'as deux déclencheurs alternatifs qui sont les paramètres de la recherche: tes 2 checkbox "cat" et "crit". Tu dois alors placer l'appel à Ajax sur ces checkbox, par onClick ou onChange par exemple.

ça peut être comme ça:

echo '<td valign="top"><br /><input type="checkbox" id="cat" name="cat" value="'.$id_cat.'"  onChange="AjaxIt(this);" /><strong>'.$name_cat.'</strong>';
et
echo '<ul><input type="checkbox" id="crit" name="crit" value="'.$id_criteria.'" onChange="AjaxIt(this);" />'.$name_criteria.'</ul>';
et la fonction générique AjaxIt(checkbox) est la suivante:

Code : Tout sélectionner

<script> function AjaxIt (checkbox){ if (checkbox.checked){ //si cochée getByAjax('result_request.php', document.getElementById('ajax'), checkbox.id + '=' + checkbox.value); } } </script>
C'est une façon plus lisible, pour ne pas avoir à écrire le getByAjax plusieurs fois et soufrir des quotes et guillemets.

Posté : 02 juil. 2007, 14:47
par béka
Ajaxit() correspond à quoi ? car moi elle n'est défini nulle part cette fonction.

Posté : 02 juil. 2007, 14:50
par sadeq
Lis bien le post c'est la fonction de l'exemple que j'ai inventé et qui fait l'appel Ajax selon le checkbox activé
ça fait trop de fonctions! mais bon, c'est plus lisible comme ça. :wink:

Posté : 02 juil. 2007, 14:55
par béka
c'est à dire que je remplace

Code : Tout sélectionner

<button onClick="getByAjax('result_request.php', document.getElementById('ajax'), objet.id + '=' + objet.value);">Search</button>
par ???

je ne vois pas comment utilisée la fonction là ?

Posté : 02 juil. 2007, 15:18
par sadeq
Ba oui, si tu utilise la solution onChange+la fonction javascript AjaxIt() que j'ai postée tu dois enlever le <Button>

Posté : 02 juil. 2007, 16:01
par béka
oui d'accord, je viens de le faire, mais je peux quand même utiliser un bouton, car vu que j'utilise des checkbox, j'aimerais qu'il y ait une validation.

J'aimerais en fait que la validation ne se fasse pas directement lorsqu'on sélectionne les checkbox mais lorsqu'on clique sur un bouton.

Posté : 03 juil. 2007, 08:40
par sadeq
ok, tu n'as qu'à passer donc les 2 paramètres 'cat' et 'crit' en même temps à la fonction getByAjax comme ça:
<button onClick="getByAjax('result_request.php', document.getElementById('ajax'), 'cat='+document.getElementById('cat')+'&crit='+document.getElementById('crit') );">Search</button>
Les paramètres sont passés à Ajax sous la forme standard:

Code : Tout sélectionner

parm1=valeur1&param2=valeur2...
Dans notre cas:

Code : Tout sélectionner

'cat='+document.getElementById('cat')+'&crit='+document.getElementById('crit')


Ainsi on a vu les 2 méthodes soit un appel Ajax par le boutton ou directement par les checkbox.

ps: désolé si j'écris les noms des fonctions en anglais mais c'est une habitude.

Posté : 03 juil. 2007, 08:58
par béka
pour passer les paramètres j'avais fais comme ça moi :

Code : Tout sélectionner

function AjaxIt (checkbox){ if (checkbox.checked){ //si cochée var explode = checkbox.name.split('/'); var id_cat = explode[1]; //var url = document.location.href="result-request.php?cat="+id_cat ; getByAjax('result-request.php?cat='+id_cat, document.getElementById('ajax'), checkbox.id + "=" + checkbox.value); } }
et là le php :
<?
echo "<table align='center'><tr>";
foreach($cat_criteria as $cat){
  $name_cat = $cat->getAttribute('name');
  $id_cat = $cat->getAttribute('id');
  echo "<td valign='top'><br /><strong>".$name_cat." : </strong>";
  foreach ($cat->childNodes as $criteria)
  {
    if ($criteria->nodeType != XML_ELEMENT_NODE) continue;
    if ($criteria->tagName == 'criteria')
    {
      $name_criteria = $criteria->getAttribute('name');
      $id_criteria = $criteria->getAttribute('id');      
      echo "<ul><input type='checkbox' id='crit' name='crit/$id_cat' value='$id_criteria' onClick='AjaxIt(this);'>$name_criteria</input></ul>";
    }
  }
}
echo "</tr></table>";

?>
mais je crois que ta façon est plus simple et peut être plus optimale.

[EDIT] : il y a un problème avec ta solution, lorsqu'on clique sur le bouton, rien ne s'affiche. COmment écrire alors cette fonction qui lui passe la valeur de crit et cat. Car en fait, la finalité du truc, c'est qu'ensuite ce soit un moteur derecherche multicritère. C'est à dire qu'il faudra certaineemnt, je pense, faire une boucle sur tout le formulaire non?

J'ai essayé d'avancer dans mes rechercehs, voilà le code que j'obtiens et je n'arrive toujours pas à afficher quoique ce soit. Pourquoi ?
Voici mon code :
<script>
function AfficheResult() {
  var critInputs = document.criteria.elements;
  var myInput;
  for ( var i = 0 ; i < critInputs.length ; i++ ) {
    myInput = critInputs[i];
    if ( myInput.type == 'checkbox' && myInput.checked ) {
      var explode = myInput.value.split('/');
      var id_cat = explode[0];
      getByAjax('result-request.php?cat='+id_cat, document.getElementById('ajax'), myInput.type.id + "=" + myInput.type.value); 
    }
  }  
}
</script>

<form name="criteria" method="POST">
<?
echo "<table align='center'><tr>";
foreach($cat_criteria as $cat){
  $name_cat = $cat->getAttribute('name');
  $id_cat = $cat->getAttribute('id');
  echo "<td valign='top'><br /><strong>".$name_cat." : </strong>";
  foreach ($cat->childNodes as $criteria)
  {
    if ($criteria->nodeType != XML_ELEMENT_NODE) continue;
    if ($criteria->tagName == 'criteria')
    {
      $name_criteria = $criteria->getAttribute('name');
      $id_criteria = $criteria->getAttribute('id');      
      echo "<ul><input type='checkbox' id='crit[]' name='crit[]' value='$id_cat/$id_criteria'>$name_criteria</input></ul>";
    }
  }
}
echo "</tr></table>";

?>
<div align="center"><button onClick="AfficheResult();">Search</button></div>
</form>
<div id="ajax"></div>
[EDIT 2]
Voilà, j'ai trouvé une solution qui marche, voici le code :
<script>
function AfficheResult() {
  var critInputs = document.criteria.elements;
  var myInput;
  for ( var i = 0 ; i < critInputs.length ; i++ ) {
    myInput = critInputs[i];
    if ( myInput.type == 'checkbox' && myInput.checked ) {
      var explode = myInput.value.split('/');
      var id_cat = explode[0];
      var id_crit = explode[1];
      getByAjax('result-request.php', document.getElementById('ajax'), 'cat='+id_cat+'&crit='+id_crit); 
    }
  }  
}
</script>

<form name="criteria">
<?
echo "<table align='center'><tr>";
foreach($cat_criteria as $cat){
  $name_cat = $cat->getAttribute('name');
  $id_cat = $cat->getAttribute('id');
  echo "<td valign='top'><br /><strong>".$name_cat." : </strong>";
  foreach ($cat->childNodes as $criteria)
  {
    if ($criteria->nodeType != XML_ELEMENT_NODE) continue;
    if ($criteria->tagName == 'criteria')
    {
      $name_criteria = $criteria->getAttribute('name');
      $id_criteria = $criteria->getAttribute('id');      
      echo "<ul><input type='checkbox' id='crit' name='crit[]' value='$id_cat/$id_criteria'>$name_criteria</input></ul>";
    }
  }
}
echo "</tr></table>";

?>
</form>
<div align="center"><button onClick="AfficheResult();">Search</button></div>

<div id="ajax"></div>
Me reste plus qu'a réglé l'affichage des résultats pour que tous s'affichent.

Posté : 03 juil. 2007, 13:23
par sadeq
J'ai une idée, puisque t'as mis le getByAjax(...) dans la boucle for, tu peux générer automatiquement des zones de réponses comme le div "ajax" selon le nombre de critères. Tu peux utiliser pour ça les fonctions DOM HTML.

Posté : 03 juil. 2007, 13:36
par béka
explique sadeq ?

Posté : 03 juil. 2007, 15:26
par sadeq
Actuellement tu a prévu un div nommé "ajax" pour recevoir le résultat de Ajax, mais puisque tu appelle la fonction getByAjax() dans la boucle for, plusieurs réponses Ajax se succéderont et finiront dans le même div (nommé ajax) ce qui fait que la dernière réponse écrasera les précédentes.

L'idée est multiplier les div récepteurs de réponses selon le nombre de critères traités n'est-ce pas ce que tu veux?

Style: si t'as 3 couples de critères (cat, crit) tu auras 3 div de réponse.

Je dis ça mais je ne sais même pas ce tu veux afficher :oops: , veux-tu m'expliquer comment est la réponse attendue suite à une sélection de plusieurs critères?

Posté : 03 juil. 2007, 15:42
par béka
si si ben c'est justement ce que je voulais faire (t'es monsieur Soleil ? Tu lis dans les pensées ?) et je ne savais pas trop comment faire. J'avais pensé faire une boucle dans mon fichier où on récupère le contenu et où on l'affiche.

Mais ta proposition m'a l'air moins lourd.

Peux-tu m'expliquer comment faire ?