11484 sujets

JavaScript, DOM et API Web HTML5

Bonjour, je cherche votre aide pour faire trier mes annonces selon le prix ou la superficie. Je ne sais pas comment procéder. Si quelqu'un peut me donner un exemple Smiley smile

Voici mon code source html avec 2 exemples pour ne pas faire long:

<div class="prix-condition">
				<span>trier par le prix</span>
				<select name="" id="select">
					<option value="Default">Default</option>
					<option value="LowToHigh">Du plus bas au plus haut</option>
					<option value="HighToLow">Du plus haut au plus bas</option>
				</select>
			</div>


      <div class="superficie-condition">
				<span>trier par la superficie</span>
				<select name="" id="select">
					<option value="Default">Default</option>
					<option value="LowToHigh">Du plus bas au plus haut</option>
					<option value="HighToLow">Du plus haut au plus bas</option>
				</select>
			</div>


<div class="container">
<div class="slider" >
<img class ="active" style="width:240px; height:170px;" src="/no_image.png">
</div>
<div class= "informations">
<a class="maquette" href="/principales/single.php?id=29"  >
 <p class='title'>location appart</p>
<p class='price'><span class='price'>Prix :</span> 10</p>
<p class='superficie'><span class='superficie'>Prix :</span> 10 m2</p>
<p class='city'> <i class='fa fa-map-marker' style='font-size:15px'></i>Ville A</p></a>
</div>
</div>
  
<div class="container">
<div class="slider" >
<img class ="active" style="width:240px; height:170px;" src="/no_image.png">
</div>
<div class= "informations">
<a class="maquette" href="/principales/single.php?id=30"  >
 <p class='title'>Location appart</p>
<p class='price'><span class='price'>Prix :</span> 20</p>
<p class='superficie'><span class='superficie'>Prix :</span> 30 m2</p>
<p class='city'> <i class='fa fa-map-marker' style='font-size:15px'></i>Ville B</p></a>
</div>
</div>
Modérateur
Bonjour,

Normalement, le tri se fait à la construction de la page (avec du php puisqu'ici il semble que ce soit du php côté serveur). Or, on n'a aucune information sur la manière dont est construit la page ici.

Sinon, il faudra sans doute faire du javascript côté client, mais ce serait du bricolage.

Amicalement,
Bonjour Parishmoni, et merci pour ta réponse.
Du côté php j'ai une page pour les fonctions où le tri est effectué selon la date:
function getAnnnonces(){
  global $bdd;
  $sql_lang = (!empty(($_SESSION['lang']) && in_array($_SESSION['lang'], ['fr','en','es']) ))? $_SESSION['lang'] : 'fr'; 
  $page = (!empty($_GET["page"]) )? intval($_GET["page"]) : 1;
  $nbr_elements_par_page=10;
  $debut=($page-1)*$nbr_elements_par_page;
  
  $sql = ' SELECT  A.*
                  ,C.nom_'.$sql_lang.' AS CATEGORIE
                  ,V.ville_'.$sql_lang.' AS VILLE
           FROM annonces A
           LEFT JOIN categories C ON C.id = A.id_categorie
           LEFT JOIN villes V ON V.id = A.id_ville
           ORDER BY A.created_date DESC
           LIMIT '.$debut.','.$nbr_elements_par_page.' ';
//Autre suite...
function afficherAnnonce(){

  $annonces = getAnnnonces();
  $images = getImagesAnnonces();
//..suite


Et la page pour afficher:

$anouncement= afficherAnnonce();

<div class="prix-condition">
				<span>trier par le prix</span>
				<select name="" id="select">
					<option value="Default">Default</option>
					<option value="LowToHigh">Du plus bas au plus haut</option>
					<option value="HighToLow">Du plus haut au plus bas</option>
				</select>
			</div>


      <div class="superficie-condition">
				<span>trier par la superficie</span>
				<select name="" id="select">
					<option value="Default">Default</option>
					<option value="LowToHigh">Du plus bas au plus haut</option>
					<option value="HighToLow">Du plus haut au plus bas</option>
				</select>
			</div>


<?php foreach ($anouncement as $anounce) {

  $id= $anounce['id'];

  $images = !empty($anounce['images']) ? $anounce['images'] : ['/no_image.png']; // array

  if (!empty($images)) {
    //boucle sur les images
    echo'<div class="container">';

     
    echo ' <div class="slider" >';
    foreach ($images as $img) {
     
      echo '<img class ="active" style="width:240px; height:170px;" src="' . $img . '">';

    }
    echo "</div>"; // fin div slider . 
  }
  echo '<div class= "informations">';
  echo '<a class="maquette" href="/principales/single.php?id='.$id.'"  > '; 
  echo "<p class='title'>" . $anounce['titre'] . "</p>";
  echo "<p class='category'><i class='fa fa-list-alt'></i> " . $anounce['CATEGORIE'] . "</p>";
  echo "<p class='price'><span class='mru'>".$lang['prix']." :</span> " . $anounce['prix'] . "</p>";
echo "<p class='superficie'> <i class='fas fa-chart-area'></i> " . $a['superficie'] ."  ". $a['unite'] . "</p>";
  echo "<p class='date'> <i class='fa fa-calendar'></i> " . $anounce['created_date'] . "</p>";
  echo "<p class='city'> <i class='fa fa-map-marker' style='font-size:15px'></i>"  . $anounce['VILLE'] . "</p>";
  echo'</a>';

  echo"</div>"; //fin div informations
  echo "</div>"; // fin div container

}


L'objectif c'est que ça soit l'utilisateur qui puisse effectuer le tri selon le prix ou la superficie, peut-être que c'est du javascript si c'est du côté client Smiley rolleyes
Modérateur
Bonjour,

Tu as raison. Dans ton cas, ça va être du javascript côté client, du fait qu'il y a plusieurs possibilités de tri et que c'est l'internaute qui choisit à la volée ce qu'il veut.

Connais-tu un peu le javascript ?

Il faut ajouter ce qu'on appelle un handler (une fonction javascript) qui se déclenchera lors d'un changement dans le select.

Note qu'un "id" doit être unique dans chaque page. Or tes deux "select" ont le même "id".

Dans cette fonction, il faut :
1) déterminer le type de l'action à effectuer (en regardant quelle balise "option" a été choisie par l'utilisateur, le numéro de cette option se trouve dans l'attribut value de la balise "select").
2) récupérer la liste des éléments concernés (a priori tous les éléments ayant la classe "container" dans ton cas° Ça se fait avec la méthode querySelectorAll()) qui se retrouve dans une sorte de liste qu'on appelle nodeList. Par exemple :
let liste = document.querySelectorAll(".container");

Il faut transformer ensuite cette nodeList en tableau via une ligne du genre :
let tableau = Array.prototype.slice.call(liste, 0);

3) trier les éléments du tableau avec une fonction de tri qui dépend de ce qui a été déterminé au 1). Voir un exemple à https://www.delftstack.com/fr/howto/javascript/sort-array-based-on-some-property-javascript/ qu'il faudra adapter.
4) ensuite, on a plusieurs choix. Soit les éléments étaient tous dans un contenant ayant par exemple la propriété css display:flex, et alors il suffit de modifier la propriété css order de chaque élément en fonction de leur position dans le tableau trié au 3), soit retirer du DOM tous les éléments et les rajouter dans l'ordre dans lequel ils sont dans le tableau trié au 3).

S'il faut détailler encore plus, dis-le !

Amicalement,
Modifié par parsimonhi (30 Jan 2022 - 00:11)
Ok, je vois. J'ai essayé ça en ajoutant les valeurs à trier dans des span.
Côté html:
<div class="conteneur-annonce">
 
<div class="tri">
				<span>trier</span>
				<select name="" onchange="trier()" id="prix-superficie">
					<option value="Default">Default</option>
					<option value="PriceLowToHigh">Prix du plus bas au plus haut</option>
					<option value="PriceHighToLow">Prix du plus haut au plus bas</option>
          <option value="SuperficieLowToHigh">Superficie du plus bas au plus haut</option>
					<option value="SuperficieHighToLow">Superficie du plus haut au plus bas</option>
 
				</select>
			</div>
 
 
        <div class="container"> 
<div class="slider" >
<img class ="active" style="width:240px; height:170px;" src="/picture0.jpg">
</div>
<div class= "informations">
<a class="maquette" href="/principales/single.php?id=32"  >
 <p class='title'>Titre1</p>
<p class='price'><span class='mru'>Prix :</span><span class='valeur'> 210</span></p>
<p class='superficie'> <i class='fas fa-chart-area'></i> <span class='valeur'>250</span>  m2</p><
p class='date'> <i class='fa fa-calendar'></i> 2022-01-28</p>
<p class='city'> <i class='fa fa-map-marker' style='font-size:15px'></i>VilleA</p>
</a>
</div>
</div>
 
        <div class="container"> 
<div class="slider" >
<img class ="active" style="width:240px; height:170px;" src="/pictures.jpg">
</div>
<div class= "informations">
<a class="maquette" href="/principales/single.php?id=32"  >
 <p class='title'>Titre2</p>
<p class='price'><span class='mru'>Prix :</span><span class='valeur'> 21</span></p>
<p class='superficie'> <i class='fas fa-chart-area'></i> <span class='valeur'>200</span>  m2</p><
p class='date'> <i class='fa fa-calendar'></i> 2022-01-28</p>
<p class='city'> <i class='fa fa-map-marker' style='font-size:15px'></i>VilleB</p>
</a>
</div>
</div>
 
</div>


Du coté javascript, on m'affiche en console que la fonction trier() n'est pas défini:
function triDonnees( className, sens) {
  // récup. des éléments à trier
  const elements = document.querySelectorAll(".conteneur-annonce");
  const datas = [];
  elements.forEach((el) => {
    const elValue = el.querySelector( `.${className} .valeur`);
    const value = parseFloat(elValue.textContent);
    datas.push([el, value]);
  });
  if( sens > 0 ){
    datas.sort((a,b) => {
      return a[1] - b[1];
    })
  }
  else {
    datas.sort((a,b) => {
      return b[1] - a[1];
    })
  }
  const elemParent = elements[0].parentNode;
  datas.forEach((el) => {
    elemParent.appendChild(el[0]);
  });
 
}
 
 
function trier(){
 
var tri= document.getElementById("prix-superficie");
 
if(tri.value=="PriceLowToHigh"){
  triDonnees( price, b[1] - a[1]);
 
}
 
else if(tri.value=="PriceHighToLow"){
  triDonnees( price, a[1] - b[1];);
 
}
 
else if(tri.value=="SuperficieHighToLow"){
  triDonnees( superficie, a[1] - b[1];);
 
}
 
else if(tri.value=="SuperficieLowToHigh"){
  triDonnees( superficie, b[1] - a[1]);
 
}

Je ne vois pas le grain de sable dans les rouages
Modérateur
Bonjour,

max30 a écrit :
Je ne vois pas le grain de sable dans les rouages
Il y en avait pas mal pourtant. Smiley cligne J'ai l'impression que tu codes un peu au hasard ! Mais au moins, tu as essayé. Donc déjà, c'est un bon point.

Voici ci-dessous une version qui devrait fonctionner. J'ai changé beaucoup de choses dans le javascript. Il y avait de l'idée, mais c'était très incomplet et parsemé de bugs. J'ai changé aussi un peu le html et les noms de classes. Il vaut mieux mettre les annonces dans un conteneur qui les regroupe, et le select pour le tri dans un autre conteneur. Comme ça, c'est plus facile pour effacer et remettre les annonces dans le html après un tri. Attention aussi dans les <span class="valeur">xxx</span> : il ne faut pas d'espace avant et après le nombre xxx. J'ai retiré ces espaces dans le code html. Ou alors il faut écrire une fonction de récupération de ces valeurs plus robuste. Les autres modifications dans le html sont cosmétiques et pas vraiment nécessaires. Voir aussi https://jsfiddle.net/parsimonhi/1tLahnmy/
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body>div {margin:1em;}
.annonce img {width:240px; height:170px;}
</style>
</head>
<body>
<div class="selecteur-de-tri">
	<span>Trier</span>
	<select onchange="trier()" id="prix-superficie">
		<option value="Default">Default</option>
		<option value="PriceLowToHigh">Prix du plus bas au plus haut</option>
		<option value="PriceHighToLow">Prix du plus haut au plus bas</option>
		<option value="SuperficieLowToHigh">Superficie du plus bas au plus haut</option>
		<option value="SuperficieHighToLow">Superficie du plus haut au plus bas</option>
	</select>
</div>
<div class="liste-des-annonces">
	<div class="annonce"> 
		<div class="slider" >
			<img class ="active" src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Warwick_Castle_May_2016.jpg/320px-Warwick_Castle_May_2016.jpg">
		</div>
		<div class= "informations">
			<a class="maquette" href="/principales/single.php?id=32">
				<p class='title'>Titre1</p>
				<p class='price'><span class='mru'>Prix : </span><span class='valeur'>210</span></p>
				<p class='superficie'>
					<i class='fas fa-chart-area'></i>
					<span class='valeur'>250</span>  m2</p>
				<p class='date'> <i class='fa fa-calendar'></i> 2022-01-28</p>
				<p class='city'> <i class='fa fa-map-marker' style='font-size:15px'></i>VilleA</p>
			</a>
		</div>
	</div>
	<div class="annonce"> 
		<div class="slider" >
			<img class ="active" src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Broadway_Tower_2012.jpg/320px-Broadway_Tower_2012.jpg">
		</div>
		<div class= "informations">
			<a class="maquette" href="/principales/single.php?id=32"  >
				<p class='title'>Titre2</p>
				<p class='price'><span class='mru'>Prix : </span><span class='valeur'>21</span></p>
				<p class='superficie'> <i class='fas fa-chart-area'></i> <span class='valeur'>200</span>  m2</p>
				<p class='date'> <i class='fa fa-calendar'></i> 2022-01-29</p>
				<p class='city'> <i class='fa fa-map-marker' style='font-size:15px'></i>VilleB</p>
			</a>
		</div>
	</div>
	<div class="annonce"> 
		<div class="slider" >
			<img class ="active" src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/59/Bratislava_Castle_R01.jpg/320px-Bratislava_Castle_R01.jpg">
		</div>
		<div class= "informations">
			<a class="maquette" href="/principales/single.php?id=32">
				<p class='title'>Titre1</p>
				<p class='price'><span class='mru'>Prix : </span><span class='valeur'>140</span></p>
				<p class='superficie'>
					<i class='fas fa-chart-area'></i>
					<span class='valeur'>220</span>  m2</p>
				<p class='date'> <i class='fa fa-calendar'></i> 2022-01-30</p>
				<p class='city'> <i class='fa fa-map-marker' style='font-size:15px'></i>VilleA</p>
			</a>
		</div>
	</div>
</div>
<script>
function compare(a, b, className, sens) {
  let valueA, valueB;
  valueA = sens * parseFloat(a.querySelector('.' + className + ' .valeur').innerHTML);
  valueB = sens * parseFloat(b.querySelector('.' + className + ' .valeur').innerHTML);
  if (valueA < valueB) return -1;
  if (valueB < valueA) return 1;
  return 0;
}

function triDonnees(className, sens) {
  let nodes = document.querySelectorAll(".annonce");
  let elements = Array.from(nodes);
  let list = nodes[0].parentNode;
  elements.sort((a, b) => compare(a, b, className, sens));
  list.innerHTML = "";
  elements.forEach(e => list.appendChild(e));
}

function trier() {
  let tri = document.getElementById("prix-superficie");
  if (tri.value == "PriceLowToHigh") {
    triDonnees("price", 1);
  } else if (tri.value == "PriceHighToLow") {
    triDonnees("price", -1);
  } else if (tri.value == "SuperficieHighToLow") {
    triDonnees("superficie", -1);
  } else if (tri.value == "SuperficieLowToHigh") {
    triDonnees("superficie", 1);
  }
}
</script>
</body>
</html>
EDIT 1: j'ai dû procéder à quelques modifications dans le code après l'avoir posté. Rien d'important.
EDIT 2: j'ai finalement remplacé :
let elements = Array.prototype.slice.call(nodes, 0);
par
let elements = Array.from(nodes);
On est en 2022. On peut désormais se le permettre.
EDIT 3: j'ai corrigé a posteriori la fonction compare() et remplacé la 2e comparaison if (valueA < valueB) return 1; par if (valueB < valueA) return 1; (un bug qui peut passer inaperçu).

Amicalement,
Modifié par parsimonhi (31 Jan 2022 - 12:18)
Super! Merci infiniment Parsimonhi. Très facile à comprendre également.
Merci encore Smiley smile