I. Introduction▲
I-A. Public visé▲
La connaissance du langage JavaScript « orienté objet » est indispensable à la compréhension de cet article. Le lecteur doit également maîtriser le HTML5 en général et plus particulièrement les formulaires et la navigation dans le DOM.
I-B. Objectifs▲
Dans ce tutoriel, nous verrons dans un premier temps comment réaliser, en JavaScript pur, un objet panier (caddy en américain) prêt à l'emploi.
En toute rigueur, cet objet devrait être exploité côté serveur, avec un framework tel que Node.js ou io.js. Il convient donc de préciser qu'un panier côté client sans stockage persistant n'est pas une bonne idée si on veut vendre beaucoup (car beaucoup d'utilisateurs font leurs achats en plusieurs temps). Donc, ce tutoriel ne se suffit pas à lui-même pour démarrer un site e-commerce.
Cependant il ne s'agit pas d'un tutoriel Node.js, aussi nous testerons dans la seconde partie de cet article notre objet panier dans une page HTML5.
I-C. Bibliothèques et outils utilisés pour les besoins de l'article▲
Tout ce que nous verrons dans cet article s'exécutera localement sur le poste de travail dans un navigateur web. Seul un éditeur de texte (Notepad++ ou SublimeText) sera donc nécessaire pour ce tutoriel.
En revanche, j'ai l'habitude d'utiliser la célèbre bibliothèque Bootstrap (du non moins célèbre réseau social Twitter) pour écrire vite des formulaires qui sont disposés sur une grille. Je ne m'en prive pas dans cet article. Mais là encore, je la télécharge directement au chargement de la page donc, rien à installer.
II. L'objet panier▲
II-A. Les fonctionnalités du panier▲
Notre panier permettra de stocker les articles choisis par le client. Il sera constitué de « lignes panier ». Chaque ligne sera dédiée à un article choisi et comprendra : le code produit, la quantité, et le prix unitaire.
Les opérations réalisables par le client avec cet objet seront :
- ajouter un article ;
- retirer un article ;
- calculer le prix d'une ligne ;
- calculer le prix total du panier.
On aura donc un objet Panier qui sera une collection d'objets LignePanier.
II-B. Code source des objets Panier et LignePanier▲
Ces deux objets sont écrits à 100 % en JavaScript.
Voici tout d'abord le code de l'objet ligne panier :
function LignePanier
(
code,
qte,
prix)
{
this.
codeArticle =
code;
this.
qteArticle =
qte;
this.
prixArticle =
prix;
this.
ajouterQte =
function(
qte)
{
this.
qteArticle +=
qte;
}
this.
getPrixLigne =
function(
)
{
var resultat =
this.
prixArticle *
this.
qteArticle;
return resultat;
}
this.
getCode =
function(
)
{
return this.
codeArticle;
}
}
Voici maintenant le code de l'objet Panier :
function Panier
(
)
{
this.
liste =
[];
this.
ajouterArticle =
function(
code,
qte,
prix)
{
var index =
this.getArticle
(
code);
if (
index ==
-
1
) this.
liste.push
(
new LignePanier
(
code,
qte,
prix));
else this.
liste[
index]
.ajouterQte
(
qte);
}
this.
getPrixPanier =
function(
)
{
var total =
0
;
for(
var i =
0
;
i <
this.
liste.
length ;
i++
)
total +=
this.
liste[
i]
.getPrixLigne
(
);
return total;
}
this.
getArticle =
function(
code)
{
for(
var i =
0
;
i <
this.
liste.
length ;
i++
)
if (
code ==
this.
liste[
i]
.getCode
(
)) return i;
return -
1
;
}
this.
supprimerArticle =
function(
code)
{
var index =
this.getArticle
(
code);
if (
index >
-
1
) this.
liste.splice
(
index,
1
);
}
}
La collection utilisée afin que Panier agrège LignePanier est le traditionnel objet JavaScript Array qui nous permettra d'accéder à chaque élément qu'il contient en parcourant ses indices.
On remarquera juste que la méthode ajouterArticle() vérifie au préalable l'existence dans le panier de l'article passé en paramètre. En cas de présence avérée, on ne fera qu'ajouter les quantités commandées.
III. Test de notre objet Panier▲
Nous pourrions bien entendu tester cet objet dans la console JavaScript. C'est d'ailleurs ce que j'ai fait pour la mise au point et le débogage. Néanmoins, il me semblait dommage d'écrire du JavaScript sans en voir le rendu dans une interface Web. De plus, les paniers que j'ai vus jusqu'à aujourd'hui étaient traités à travers des sessions (cookies…) ou directement dans le serveur. Alors j'ai pensé qu'il pouvait être intéressant de tenter l'aventure en HTML5 en manipulant le DOM de la page.
III-A. Le cahier des charges▲
Comme un dessin est souvent préférable à un long discours, vous trouverez ici l'interface Web qui est attendue :
III-B. La page HTML5▲
Sans plus attendre, voici le source de la page :
<!
doctype html
>
<html lang
=
"fr"
>
<head>
<meta charset
=
"UTF-8"
>
<title>Panier HTML5 + JavaScript</title>
<link href
=
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"
rel
=
"stylesheet"
>
<script type
=
"text/javascript"
src
=
"panier.js"
></script>
<script type
=
"text/javascript"
>
function ajouter
(
)
{
var code =
parseInt
(
document
.getElementById
(
"id"
).
value);
var qte =
parseInt
(
document
.getElementById
(
"qte"
).
value);
var prix =
parseInt
(
document
.getElementById
(
"prix"
).
value);
var monPanier =
new Panier
(
);
monPanier.ajouterArticle
(
code,
qte,
prix);
var tableau =
document
.getElementById
(
"tableau"
);
var longueurTab =
parseInt
(
document
.getElementById
(
"nbreLignes"
).
innerHTML);
if (
longueurTab >
0
)
{
for(
var i =
longueurTab ;
i >
0
;
i--
)
{
monPanier.ajouterArticle
(
parseInt
(
tableau.
rows[
i].
cells[
0
].
innerHTML),
parseInt
(
tableau.
rows[
i].
cells[
1
].
innerHTML),
parseInt
(
tableau.
rows[
i].
cells[
2
].
innerHTML));
tableau.deleteRow
(
i);
}
}
var longueur =
monPanier.
liste.
length;
for(
var i =
0
;
i <
longueur ;
i++
)
{
var ligne =
monPanier.
liste[
i];
var ligneTableau =
tableau.insertRow
(-
1
);
var colonne1 =
ligneTableau.insertCell
(
0
);
colonne1.
innerHTML +=
ligne.getCode
(
);
var colonne2 =
ligneTableau.insertCell
(
1
);
colonne2.
innerHTML +=
ligne.
qteArticle;
var colonne3 =
ligneTableau.insertCell
(
2
);
colonne3.
innerHTML +=
ligne.
prixArticle;
var colonne4 =
ligneTableau.insertCell
(
3
);
colonne4.
innerHTML +=
ligne.getPrixLigne
(
);
var colonne5 =
ligneTableau.insertCell
(
4
);
colonne5.
innerHTML +=
"<button class=
\"
btn btn-primary
\"
type=
\"
submit
\"
onclick=
\"
supprimer(this.parentNode.parentNode.cells[0].innerHTML)
\"
><span class=
\"
glyphicon glyphicon-remove
\"
></span> Retirer</button>"
;
}
document
.getElementById
(
"prixTotal"
).
innerHTML =
monPanier.getPrixPanier
(
);
document
.getElementById
(
"nbreLignes"
).
innerHTML =
longueur;
}
function supprimer
(
code)
{
var monPanier =
new Panier
(
);
var tableau =
document
.getElementById
(
"tableau"
);
var longueurTab =
parseInt
(
document
.getElementById
(
"nbreLignes"
).
innerHTML);
if (
longueurTab >
0
)
{
for(
var i =
longueurTab ;
i >
0
;
i--
)
{
monPanier.ajouterArticle
(
parseInt
(
tableau.
rows[
i].
cells[
0
].
innerHTML),
parseInt
(
tableau.
rows[
i].
cells[
1
].
innerHTML),
parseInt
(
tableau.
rows[
i].
cells[
2
].
innerHTML));
tableau.deleteRow
(
i);
}
}
monPanier.supprimerArticle
(
code);
var longueur =
monPanier.
liste.
length;
for(
var i =
0
;
i <
longueur ;
i++
)
{
var ligne =
monPanier.
liste[
i];
var ligneTableau =
tableau.insertRow
(-
1
);
var colonne1 =
ligneTableau.insertCell
(
0
);
colonne1.
innerHTML +=
ligne.getCode
(
);
var colonne2 =
ligneTableau.insertCell
(
1
);
colonne2.
innerHTML +=
ligne.
qteArticle;
var colonne3 =
ligneTableau.insertCell
(
2
);
colonne3.
innerHTML +=
ligne.
prixArticle;
var colonne4 =
ligneTableau.insertCell
(
3
);
colonne4.
innerHTML +=
ligne.getPrixLigne
(
);
var colonne5 =
ligneTableau.insertCell
(
4
);
colonne5.
innerHTML +=
"<button class=
\"
btn btn-primary
\"
type=
\"
submit
\"
onclick=
\"
supprimer(this.parentNode.parentNode.cells[0].innerHTML)
\"
><span class=
\"
glyphicon glyphicon-remove
\"
></span> Retirer</button>"
;
}
document
.getElementById
(
"prixTotal"
).
innerHTML =
monPanier.getPrixPanier
(
);
document
.getElementById
(
"nbreLignes"
).
innerHTML =
longueur;
}
</script>
</head>
<body>
<section class
=
"container"
>
<article class
=
"well form-inline pull-left col-lg-5"
>
<legend>Gestion du panier</legend>
<label class
=
"col-lg-3"
>
Identifiant</label>
: <input type
=
"number"
id
=
"id"
style
=
"width:120px"
class
=
"input-sm form-control"
></input><br><br>
<label class
=
"col-lg-3"
>Quantité</label>
: <input type
=
"number"
id
=
"qte"
style
=
"width:120px"
class
=
"input-sm form-control"
></input><br><br>
<label class
=
"col-lg-3"
>
Prix</label>
: <input type
=
"number"
id
=
"prix"
style
=
"width:120px"
class
=
"input-sm form-control"
></input><br><br>
<button class
=
"btn btn-primary"
type
=
"submit"
onclick
=
"ajouter()"
><span class
=
"glyphicon glyphicon-shopping-cart"
></span>
Ajouter au panier</button>
</article>
</section>
<section class
=
"container"
>
<article class
=
"well form-inline pull-left col-lg-5"
>
<legend>Contenu du panier</legend>
<table id
=
"tableau"
class
=
"table"
>
<thead>
<tr>
<th>Code</th>
<th>Qte</th>
<th>Prix unitaire</th>
<th>Prix de la ligne</th>
<th>Supprimer</th>
</tr>
</thead>
</table>
<br><label>Prix du panier total</label>
: <label id
=
"prixTotal"
></label>
<label id
=
"nbreLignes"
hidden>0</label>
</article>
</section>
</body>
</html>
Le scénario retenu pour coder cette page est basé sur la gestion de deux événements majeurs, un clic sur le bouton ajouter ou supprimer. Comme on n'utilise pas de session, il est difficile de garder en mémoire le contenu du panier. Aussi j'ai choisi de recharger le panier depuis le tableau d'affichage en bas de page à chaque clic sur l'un des boutons. Le nombre de lignes du panier sera lu et écrit dans le champ caché id= ''nbreLignes''.
IV. Conclusion▲
Cet article a permis de voir comment implémenter un panier en JavaScript comme on l'aurait fait avec n'importe quel autre langage. Car aujourd'hui, JavaScript est un langage aussi noble que Java ou PHP, surtout depuis qu'il s'exécute dans des serveurs. D'ailleurs, dans un prochain tutoriel je montrerai comment faire tourner ce panier plus proprement côté serveur avec Node.js.
Nous tenons à remercier SylvainPV et Vermine pour la relecture technique et f-leb pour la relecture orthographique de cet article.