React:Form :Ajouter un produit

Dans cette partie on va créer un formulaire pour ajouter un produit
Produit(id,nom,prix,qteStock)

Afin de créer un projet crud pour gérer les produits on besoin de créer deux type de projet:

BackEnd :Nodejs+ExpressJs+mysql:pour créer les RestApis
FrontEnd :React+Axios pour consommer les apis
  1. Projet: VentesReactNodeJS :La structure
  2. ├──VentesReactNodeJS
    │    ├── backEndProject
    │    │     ├── config
    │    │     │   ├── config.js
    │    │     ├──database
    │    │     │   ├── createDatabase.js
    │    │     ├──src
    │    │     │  ├──models
    │    │     │  │     ├──Produit.js      
    │    │     │  │     ├──Utilisateur.js
    │    │     │  │     ├──Vente.js
    │    │     │  ├──controllers
    │    │     │  │     ├──ProduitController.js
    │    │     │  │     ├──UtilisateurController.js
    │    │     │  │     ├──VenteController.js
    │    │     │  ├── routes
    │    │     │  │     ├──ProduitRoutes.js
    │    │     │  │     ├──UtilisateurRoutes.js
    │    │     │  │     ├──VenteRoutes.js
    │    ├── serveur.js
    │    
    │  
    │    ├── front_end_project
    │    │     
    │    │   src ├── App.js
    │    │       ├──components
    │    │       │  ├──Produits
    │    │       │  │     ├──ajouter.js
    │    │       │  │     ├──liste.js
    │    │       │  │     ├──modifier.js
    │    │       │  ├──Utilisateurs
    │    │       │  │     ├──ajouter.js
    │    │       │  │     ├──liste.js
    │    │       │  │     ├──modifier.js
    │    │       │  ├── Ventes
    │    │       │  │     ├──vendre.js
    │    │       │  │     ├──facture.js
    │____│_____ _│__│_____├──liste.js
    
    
Le projet backEndProject va contenir les traitement métier de notre application FullStack:
backEndProject
├──src
│  ├─models
│   │ ├Produit.js 
│   │  ├─objet Produit(id,nom,prix,qtestock)
│   │  ├─insert(produit) :fonction qui permet insert into table
│   │  ├─afficherAll :return select * from produits
│   │  ├─supprimre(id):return delete from produit where id=?
│   │  ├─modifier(id,produit):return upate produit set ? where id=?
│   │  ├─......

│   ├─controllers
│   │ ├─ProduitController.js
│   │  ├─insert(request):appel Produit.insert(produit)
│   │  ├─afficherAll():appel Produit.afficherAll(produit)
│   │  ├─supprimer(request):appel Produit.supprimer(produit)
│   │  ├─modifier(request):appel Produit.modifier(id,produit)
│   │  ├─.....

│  ├─routes
│  │ ├─ProduitRoutes.js
│  │  ├─Route.get('/',ProduitController.afficherAll)
│  │  ├─Route.post('/ajouter',ProduitController.insert)
│  │  ├─Route.get('/:id',ProduitController.detail)
│  │  ├─.....
Le projet front_end_project va contenir des component(View+traitements) qui appel au services du backEndProject
├──front_end_project
│  ├─components
│    ├─Produits
│      ├─ajouter.js
│      │  ├─View :formulaire HTML
│      │  ├─JavaScript JSX:traitements
│      │     ├─ajouter():consome l'api du backEndProject avec AXIOS => insert() du controllers
..............

on aura besoin

  1. Node.js et le module mysql pour intéroger la base de données
  2. le framework Express pour générer les REST APIs
  3. le module Axios de React pour consommer les Rest Apis crées dans nodeJs project

BackEnd Créer les Apis :backEndProject

Dans cette partie on va créer un projet avec Nodejs+ExpressJS+Mysql afin de créer les RestApi pour :

  1. 1GET http://localhost:8081/produits :Afficher la liste des produits
  2. 2POST:http://localhost:8081/produits/add Ajouter un produit
  3. 3Delete:http://localhost:8081/produits/:id :Supprimer un produit passé en paramètre
  4. 4PUT: http://localhost:8081/produits/id/modifier :Modifier un produit passé en paramètres

Créer la base de données ventesgestions et table Produit

Installer un SGBD mysql et démarer le service mysql

Télécharger mysql SGBD ,Dans ce tp on utilise Xampp server https://www.apachefriends.org/fr/download.html
mais vous pouvez utilsé n'importe quelle SGBD mysql

Installer le module mysql

Un projet nodeJs utilise plusieurs bibiothèque javasript nommées modules
Afin de travailer avec mysql on doit installer le module mysql

npm install mysql2 --save

Installer ExpressJs

npm install express --save

4.Créer le fichier CreerDBandTables.js

/*Importer le module mysql qui permet de gérer les transaction dans une base de données mysql */
var mysql = require('mysql2');

//créer une connexion à la base de données
var con = mysql.createConnection({
host: "localhost", /*le serveur de la base de données*/
user: "root", /*Utilisateur de la base de données*/
password: "",/*le mot de passe de l'utilisateur de la base de données*/
port: "3306", /*le serveur de la base de données*/
});

/*Créer la base de données */
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
con.query("CREATE DATABASE if not exists databaseReact", function (err, result) {
if (err) throw err;
/*se connecter à la base de données crée puis créer les tables */
var con = mysql.createConnection({
host: "localhost", /*le serveur de la base de données*/
user: "root", /*Utilisateur de la base de données*/
password: "",/*le mot de passe de l'utilisateur de la base de données*/
port: "3306", /*le serveur de la base de données*/
database: "databaseReact" /*le nom de la base de données à Créer manullement*/
});

//se connecter en utlisant con crée
con.connect(function(err) {
/*err:contient error de connexion*/
/*afficher erreur de connexion s'il existe*/
if (err) throw err;
/*pas d'erreur donc on peut exécuter des requête sql */
/*Créer la table produit */
var sql = "CREATE TABLE produit(id int primary key auto_increment,nom varchar(25),prix float,qtestock int)";
/*Exécuter la requete sql crée*/
con.query(sql, function (err, result) {
if (err) throw err;
console.log("Table produit est crée");
});
});
});
});

5.Exécuter le script SQL pour créer la base de données

node createDatabase.js

1.Créer le fichier config/config.js de configuration de la connexion à la base de données

var mysql = require('mysql2');
var connection = mysql.createConnection({
host: "localhost", /*le serveur de la base de données*/
port:"3306",/*le port du service mysql*/
user: "root", /*Utilisateur de la base de données*/
password: "",/*le mot de passe de l'utilisateur de la base de données*/
database: "databaseReact" /*le nom de la base de données à Créer manullement*/
});
//connexion à la base de données
connection.connect(function(error){
if(!!error) {
console.log(error);
} else {
console.log('Connected..!');
}
});

module.exports = connection;

3.Créer le dossie src contenant le code source de l'applications

Afin d'organiser le projet on besoin de créer les dossiers suivants

  1. src/models :contenant les model du projet produit ,utilisateur et ses fonctions de CRUD
  2. src/routes :contenant le mapping entre les requêtes http est la méthode à exécuter
  3. src/controllers :contient les méthode à exécutée selon chaque route reçues

Model: Créer le fichier src/models/Produit.js

Ce fichier représente le module de l'entité produit(id,nom,prix,qtestock) contenant:

  1. Un objet Produit
  2. Les fonctions CRUD:
    • insert
    • update
    • delete
    • detail
/*importer le fichier de configuration de connexion à la base de données*/
var connexion = require('./../../config/config');
/*Créer un objet de type Produit*/
var Produit = function(produit){
this.id = produit.id;
this.nom = produit.nom;
this.prix = produit.prix;
this.qtestock = produit.qtestock;
};

/**1.insert**/
/*Ajouter à l'objet Produit la fonction insert qui permet d'ajouter un produit dans la table produit*/
Produit.insert = function (produit, result) {
/*produit :sera renseigner par le controlleur contenant l'objet à insérer dans la table produit
result:un objet qui contiendra la réponse à envoyer au controlleur :ProduitController
*/
/*Exécuter la requêtes SQL insert into produit*/
connexion.query("INSERT INTO produit set ?", produit, function (err, res) {
/*
function (err, res):la méthode de callback sera exécuté aprés l'exécution de la commande insert into
err:contient l'erreur sql reçu
res:contient la reponse de la methode query
*/
/*Si la fonction query délenche une erreur*/
if(err) {
console.log("error: ", err);
result(err, null);
}
/*Si la fonction query s'exécute sans erreur on envoie res.insertId :c'est la valeur de la primary key de l'objet inséré */
else{
console.log(res.insertId);
result(null, res.insertId);
}
});
};


//vérifier si un attribut est vide
Produit.verifier=function(produit)
{
if(produit.nom=='' || produit.prix==0 || produit.qtestock==0)
return true;
};
/*Exporter la classe pour pouvoir l'importer dans le controller */
module.exports= Produit;

Controller: Créer le fichier src/controllers/ProduitController.js

Permet de gérer la communication entre le model Produit et les et le projet React :frontEndProject

/*Importer les fonctions insert , update, delete , select... */
const ProduitModel = require('../models/Produit')
/*Insérer un nouveau produit dans la table produit*/
exports.insert = (req, res) =>{
const produit_nouveau = new ProduitModel(req.body);
/*Vérifier si tout les champs sont rempli*/
if(ProduitModel.verifier(produit_nouveau))
{
res.json({status: false, message: 'Erreur le produit non ajouté', data: null})
}else{
ProduitModel.insert(produit_nouveau, (err, produit)=>{
if(err)
/*si erreur envoyer l'erreur*/
res.send(err);
/*si Ok envoyer un objet json de la forme:
{
status:true;
message:"le produit est bien ajouté",
data:id du produit inséré
}
*/
res.json({status: true, message: 'Le produit est bien ajouté', data: produit.insertId})
})
}
}

Routes: Créer le fichier src/routes/ProduitRoutes.js

/*importer express js pour manipuler les routes*/
const express = require('express');
/*importer le module Router de express js*/
const routerProduits = express.Router();
/*imporer produitController*/
const produitController = require('../controllers/ProduitController');


/*la route:=> produits/ajouter ,avec la méthode POST
ajouterValider:=>la fonction du ProduitController qui permet d'insérer un produit dans la table produit*/
routerProduits.post('/ajouter', produitController.insert);
module.exports = routerProduits

Serveur Nodejs: Créer le fichier Serveur.js

Permettant de demarer le serveur des APIs

Installer cors

npm install cors --save
const express = require('express');
const bodyParser = require('body-parser');
/*Pemert d'authoriser la consommation des api à partir d'un autre serveur
dans ce cas projet React */
const cors = require('cors');
const app = express();
/*activer le cros domaine */
app.use(cors())
const port = 8081;
// activer le traitement des request de type application/x-www-form-rulencoded
app.use(bodyParser.urlencoded({extended: false}));
//activer le traitement des request de type application/json
app.use(bodyParser.json());

//importer le fichier de routage pour le produit
const produitRoutes = require('./src/routes/ProduitRoutes');
/*Créer les apis pour Produit*/
app.use('/apis/produits/', produitRoutes );
/*Démarer le serveur backEnd*/
app.listen(port, ()=>{
console.log('Serveur est démaré ${port}');
});

FrontEnd Créer les Vues :front_end_project

Créer un projet React

npx create-react-app font_end_project

Créer la component produits/ajouter

On peut créer les component manuellement (un fichier .js) mais afin d'accélérer et simplifier la création des component on install:

npm install --save-dev create-react-component-folder

Puis pour créer la component produits/ajouter on se positionnne dans le dossier src puis on lance la commande

cd src
npx crcf components/Produits/ajouter
/*ajouter.js:le contenu par défaut */
import React, { Component } from "react";

class Ajouter extends Component {
render() {
return <div>Ajouter</div>;
}
}

export default Ajouter;

Installer bootstrap

npm install react-bootstrap bootstrap@5.1.3
Le dossier node_modules\bootstrap est crée contenant les style boostrap
l'étape suivante est ajoute bootstrap.css dans la component principale App.js et importer la component navigation.js
import './App.css';
/*importer les styles boostrap*/
import 'bootstrap/dist/css/bootstrap.min.css';
/*importer la component ajouter*/
import Ajouter from './components/Produits/ajouter'

function App() {
return (
/*Ajouter la component ajouter.js*/
<div>
<Ajouter/>
</div>
);
}

export default App;

Installer Axios

npm install axios --save

Modifier le fichier ajouter.js en ajoutant le formulaire pour ajouter un produit

import React, { Component } from "react";
import axios from "axios";

class Ajouter extends Component {
constructor(props) {
super(props);

/*Créer le state du component*/
this.state = {
produit:{
id: null,
nom: "",
qtestock:0,
prix:0
},
message:"",/*Stocker la réponse du serveur*/
statusResponse:""/*Stocker l'état de la reponse 200,404..*/
};
/*Enregister la méthode changerEtat*/
this.changerEtat = this.changerEtat.bind(this);
}


changerEtat(event) {
this.setState({produit:{
...this.state.produit,
/*changer la valeur de l'attribut
[event.target.name]=><input name="nom"
event.target.value => input value=""*/
[event.target.name]: event.target.value
}});
}



/*Envoyer un nouveau produit*/
ajouterProduit = async e => {
await axios.post('http://localhost:8081/apis/produits/ajouter', this.state.produit)
.then(response => {
/*est la réponse du serveur nodejs :
data: {status: true, message: 'Le produit est bien ajout�'}
headers: {content-length: '56', content-type: 'application/json; charset=utf-8'}
request: XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
status: 200
statusText: "OK"
*/
//Changer le State
this.setState({statusResponse:response.data.status,
message:response.data.message});
/*le produit est bien ajouté initialiser les input et l'objet produit du sate*/
if(this.state.statusResponse==true)
{
this.setState({produit:{
...this.state.produit,
nom: "",
prix: 0,
qtestock: 0
}});

}
});;
};

render() {
let couleur="";
if (this.state.statusResponse==true) {
couleur ="alert alert-success";
}
if (this.state.statusResponse==false) {
couleur ="alert alert-danger";
}

return (
<div className="container">
<div className="row">
<fieldset className="border p-2">
{/*Afficher le message si on a reçu une reponse serveur*/}
{this.state.message.length > 0 &&
<div className={ couleur} role="alert">
{this.state.message}
</div>
}

<legend className="w-auto">Ajouter un produit</legend>
<div className="form-group mb-3">
<input
type="text"
className="form-control"
placeholder="Enter le nom"
name="nom"
value={this.state.produit.nom}
onChange={e => this.changerEtat(e)} />
</div>
<div className="form-group mb-3">
<input
type="number"
className="form-control"
placeholder="Enter le prix"
name="prix"
value={this.state.produit.prix}
onChange={e => this.changerEtat(e)}/>
</div>
<div className="form-group mb-3">
<input
type="number"
className="form-control"
placeholder="Enter le qtestock"
name="qtestock"
value={this.state.produit.qtestock}
onChange={e => this.changerEtat(e)} />
</div>
<button onClick={this.ajouterProduit} className="btn btn-secondary btn-block">Ajouter</button>
</fieldset>
</div>
</div>
);
}
}

export default Ajouter;

Demarer le backEndProject

backEndProject>node Serveur.js

Demarer le front_end_project

font_end_project>npm start