Vous êtes sur la page 1sur 18

Mise en place d’une application CRUD avec VueJS 3

Dans cet atelier, on va effectuer des opérations CRUD à l'aide de l'API Web dans VueJS. Les services
qu’on va consommer provenant d’un fichier JSON. En effet, on va apprendre comment créer et
consommer un RESTful. Pour gérer les données dans un serveur, on utilisera GET, POST, PUT et Delete
à travers HttpClient API. De plus, on va intégrer le Framework Bootstrap aux interfaces créées.

Vue.js est un Framework progressif pour JavaScript utilisé pour créer des interfaces Web et des
applications d'une page (SPA). Vue.js peut également être utilisé pour le développement d'applications
de bureau et mobiles avec les frameworks Ionic et Electron.

1. Créer un nouveau projet VueJS

Pour installer le projet Vue, nous devons avoir Vue CLI installé sur notre système de développement.
Exécutez la commande suivante pour installer Vue CLI :
npm install -g @vue/cli

Utilisez la commande suivante pour installer le projet vue.


vue create monprojet

Nous devons choisir la version 3 de Vue.

Rendez-vous sur le projet de vue :


cd monprojet

Ouvrez le projet vue dans l’éditeur Visual Studio Code :


code .

Exécutez la commande pour démarrer l'application sur le navigateur :


npm run serve

Une fois le serveur hébergé et l'application démarrée, vous pouvez accéder à http://localhost:8080/.
La réponse doit être quelque chose de similaire à la sortie, comme ci-dessous.
2. Les composants d’un projet Vue

Presque tous les Framework front-end nous permettent de créer des composants que nous pouvons
réutiliser à plusieurs endroits sur le même site Web ou sur des sites Web différents. Certains exemples
incluent une barre de recherche, un formulaire de connexion, un composant d'affichage du produit,
etc. Dans Vue, les fichiers avec l'extension ".vue" sont appelés composants de fichier unique. Ces
composants de fichier unique sont composés de HTML, JavaScript et CSS.

<template>
<!-- HTML Template -->
</template>

<script>
export default {}
</script>

<style>
</style>

 La partie template contient le code HTML du composant.


 La balise de script contient le code définissant le comportement personnalisé du composant.
 La balise style contient le CSS du composant.
 src/components et src/views contiennent tous nos composants.
3. La structure d’un projet Vue

Passons en revue la structure des dossiers de notre projet Vue nouvellement créé :

*public *— contient le fichier HTML principal de notre projet

*src/assets *— stocke les fichiers multimédias comme les images, les logos, etc.

*src/components *— stocke tous les composants réutilisables de notre projet. Ces composants ne
sont pas uniques à un itinéraire spécifique.

En dehors de cela, nous avons aussi des fichiers importants :

main.js **— c'est le point de départ de notre projet. Ici, nous importerons notre composant racine
**App.vue, notre fichier de routeur index.js et la méthode createApp.

La structure des dossiers n'est pas obligatoire telle qu’elle est, nous pouvons la personnaliser selon nos
besoins.

4. Installer les dépendances


a. Bootstrap

Bootstrap est une collection d'outils utiles à la création du design de sites et d'applications web.
npm install bootstrap

b. Axios

Pour les projets qui doivent s'interfacer avec une API REST, Axios est un client HTTP léger basé sur le
service $http et similaire à l'API Fetch.
Axios est basé sur des promesses et nous pouvons donc profiter de async et await plus lisible. Nous
pouvons également intercepter et annuler des demandes, et il existe une protection côté client
intégrée contre la falsification des demandes intersites.
npm install axios

c. Router

Le terme « Applications monopages » (SPA) indique qu'une seule page est chargée. Cette dernière est
ensuite mise à jour dynamiquement en fonction des besoins. Bien que cela soit puissant, il y a tout de
même un défaut principal : les utilisateurs ont besoin d'URL différentes pour distinguer les différentes
pages les unes des autres. Sinon, à chaque fois qu'un utilisateur essaie de revenir en arrière, il
obtiendra toujours la même page !

Pour résoudre ce problème, tous les grands Frameworks disposent d'une solution de routage. La
solution recommandée par Vue est la bibliothèque officielle vue-router.

Pour ajouter Vue Router à notre application, nous utiliserons Vue CLI :
vue add router

Lorsqu'on demande de choisir le mode historique, choisissez oui.

Une fois l'installation terminée, vous devriez observer que la CLI a modifié un certain nombre de
fichiers afin de s'assurer que tout fonctionne correctement. Si vous ouvrez votre fichier main.js, vous
verrez que Vue CLI a automatiquement configuré la propriété Router en la rattachant à votre instance
de Vue. De plus, un nouveau fichier est apparu, essentiel à la compréhension du routage :
router/index.js.

5. Installer le serveur JSON.

Le JavaScript Object Notation (JSON) est un format standard utilisé pour représenter des données
structurées de façon semblable aux objets Javascript. Il est habituellement utilisé pour structurer et
transmettre des données sur des sites web (échanger des données entre un serveur et un client).

json-server nous permet d’imiter une API et de fournir un accès dynamique aux données. Cela veut dire
qu’on peut lire, ajouter, mettre à jour et supprimer des données (GET, POST, PUT / PATCH, DELETE).

Vous pouvez installer json-server en global ou bien dans votre projet en utilisant la commande :
npm install -g json-server

6. Dans le nouveau projet Vue déjà généré, créer un répertoire intitulé backend dans lequel un
fichier ayant le nom database.json.

Ce fichier aura les données fake JSON dont la structure est la suivante :

{
"livres": [
{
"id": 1,
"isbn": "9882348560755",
"titre": "HAVE FUN LEAR ENGLISH YEAR 4 BASIC EDUCATION",
"maisonedition": "Eyrolles",
"annedition": "2021",
"auteur": "CNP",
"prix": 2,
"qtestock": 10,
"categorie": "LISTES SCOLAIRES MINISTERE CNP",
"image": "6192202608000_1_m.jpg"
},
{
"id": 2,
"isbn": "9782401064218",
"titre": "annabac sujets & corrigés",
"maisonedition": "Eyrolles",
"annedition": "2020",
"auteur": "CNP",
"prix": 48,
"qtestock": 15,
"categorie": "LISTES SCOLAIRES MINISTERE CNP",
"image": "9782401064218_1_75.jpg"
}
]
}

7. Dans l’invite de commande, au niveau de la racine de l’application, démarrer le serveur JSON.


Ce serveur devra être en marche tout au long de l’exécution de l’application.

La commande qui permet de démarrer le serveur fake JSON est :

json-server –watch chemin/nomfichier.JSON [--port numport]

Sachant que le numéro de port par défaut s’il n’est pas explicitement déclaré est 3000.

Dans notre cas ça sera :

json-server --watch backend/database.json --port 3003

8. Dans le dossier « src/assets » du projet Vue, créer un répertoire intitulé « images ». Puis y
télécharger les différentes images de produits qu’on va afficher dans notre site.

9. Mettre en place des imports dans main.js

Vue CLI crée plusieurs dossiers et fichiers. Le point de départ est public/index.html et "src/main.js".
Mais le component qui sert de point d'entrée est donc App.vue

Avec une application Vue, aucun code HTML ne sera écrit dans le fichier index.html. Votre code HTML
sera écrit dans la section de chacun de vos components
Le fichier main.js sert à configurer notre projet. Il précise les composants à utiliser (import App from
'./App.vue'), initialiser des variables globales (Vue.config.productionTip = false) et précise où le rendu
doit être effectué ($mount('#app'))).

Ce fichier est en quelque sorte le point central de l'application.

import { createApp } from 'vue'


import App from './App.vue'
import router from './router'
import 'bootstrap/dist/css/bootstrap.min.css'

createApp(App).use(router).mount('#app')

10. Créer les composants

Rendez-vous dans le répertoire src/components, ici nous devons créer les composants suivants. Ces
composants géreront les données dans notre application Vue.Js.

 CreateComponent.vue
 EditComponent.vue
 ListComponent.vue

Le squelette de code à mettre dans chacun des composants est la suivante :


<template>
<div class="row justify-content-center">
<div class="col-md-6">
<!-- Contenu -->
</div>
</div>
</template>

<script>
export default {
data() {
return {
}
}
}
</script>
</div>

11. Mise en place des routes

Il existe deux composants principaux que Vue Router utilise et que vous devrez apprivoiser pour vos
applications :

<router-view></router-view> - il définit la zone de la page dans laquelle apparaîtra le composant que


nous définissons dans chaque route. Ce component est fourni avec la librairie vue-router et agit
comme conteneur pour rendre les routes que nous avons défini.

<router-link></router-link> - similaire à la balise anchor en HTML, ce composant permet également


la navigation de l'utilisateur dans l'application. Cependant, il est privilégié par rapport à l'utilisation
d'une balise d'ancrage standard, car il dispose de fonctionnalités intégrées, comme le fait qu'il évite
de recharger systématiquement la page.

Ces deux composants constituent la base de l'utilisation de Vue Router dans nos composants. Ils
facilitent la navigation dans une application Vue.

Ouvrez le fichier router/index.js puis modifiez son contenu ainsi :

import { createRouter, createWebHistory } from 'vue-router'


import ListComponent from '../components/ListComponent'
import CreateComponent from '../components/CreateComponent.vue'
import EditComponent from '../components/EditComponent'
const routes = [
{
path: '/',
name: 'Home',
component: ListComponent
},
{
path: '/add',
name: 'Ajout',
component: CreateComponent
},
{
path: '/edit/:id',
name: 'Modification',
component: EditComponent
}
]

const router = createRouter({


history: createWebHistory(process.env.BASE_URL),
routes
})

export default router

L'option d'historique lors de la création de l'instance de routeur nous permet de choisir parmi
différents modes d'historique.

Le mode d'historique de hachage est créé avec createWebHistory.

Vue dispose d'un système de fichiers en cascade qui déterminera les variables d'environnement pour
votre application. Le fichier principal étant un .env

BASE_URL - cela correspond à l'option publicPath dans vue.config.js et est le chemin de base sur lequel
votre application est déployée.

12. Configuration de la navigation avec Bootstrap et Router View dans Vue


a. Créez le fichier src/views/NavBar.vue, nous définissons ici le composant Bootstrap Navigation
et la directive router-link.
<template>

<!-- Nav bar -->


<nav class="navbar navbar-dark bg-primary justify-content-between flex-
nowrap flex-row">
<div class="container">
<a class="navbar-brand float-left">Projet</a>
<ul class="nav navbar-nav flex-row float-right">
<li class="nav-item">
<router-link class="nav-link pr-3" to="/"> Liste </router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" to="/add"> Ajout </router-link>
</li>
</ul>
</div>
</nav>

</template>

Le <router-link> est le composant permettant de faciliter la navigation de l'utilisateur dans une


application vue activée par un routeur.

b. Accédez au fichier src/App.vue, nous définissons ici la directive router-view et nous appelons
le composant NavBar.

<template>
<div>
<NavBar />
<!-- Router view -->
<div class="container mt-5">
<router-view></router-view>
</div>
</div>
</template>

<script>
import NavBar from './views/NavBar.vue'

export default {
name: 'App',
components: {
NavBar
}
}
</script>
Le composant <router-view> est le composant principal responsable du rendu du composant
correspondant pour le chemin fourni.

13. Créer les services avec axios

On a besoin de données venant d’un serveur notamment grâce à l’utilisation d’un service REST. Nous
allons consommer les données JSON. Pour cela nous allons mettre en place les requêtes axios avec les
différentes méthodes GET, POST, PUT et DELETE.

Nous allons créer une classe de services dans src/services/LivreService.js ayant le contenu suivant :

import Axios from '../api/Axios'

class ProductService {
getAll() {
return Axios.get("/livres")
}
add(data) {
return Axios.post("/livres", data);
}
getOne(id) {
return Axios.get(`/livres/${id}`)
}
edit(id,data) {
return Axios.put(`/livres/${id}`,data);
}
del(id) {
return Axios.delete(`/livres/${id}`)
}
}
export default new ProductService();

14. Afficher la liste des données et supprimer les données dans Vue

Maintenant, nous allons afficher les données sous forme d’un tableau à l'aide des composants
Bootstrap Table, et nous allons faire appel à la requête axios.get() pour restituer les données du
serveur à partir de la classe ProductService.

<template>
<div class="row">
<div class="col-md-12">
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th></th>
<th>Titre</th>
<th>Edition</th>
<th>Auteur</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="liv in Livres" :key="liv.id">
<td><span v-if="liv.image.indexOf('.')>-1"><img
:src="require(`../assets/images/${liv.image}`)" :alt="liv.titre"
width="70"></span></td>
<td>{{ liv.titre }}</td>
<td>{{ liv.maisonedition }}</td>
<td>{{ liv.auteur }}</td>
<td>
<router-link :to="{name: 'Modification', params: {
id: liv.id }}" class="btn btn-success">Edit
</router-link>
<button @click.prevent="deleteLivre(liv.id)"
class="btn btn-danger">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>

<script>

import ProductService from "../services/LivreService";


export default {
data() {
return {
Livres: []
}
},
created() {
ProductService.getAll().then(res => {
this.Livres = res.data;
}).catch(error => {
console.log(error)
});
},
methods: {
deleteLivre(id){

let indexOfArrayItem = this.Livres.findIndex(i => i.id === id);

if (window.confirm("Etes-vous sû de vouloir supprimer ?")) {


ProductService.del(id).then(() => {
this.Livres.splice(indexOfArrayItem, 1);
}).catch(error => {
console.log(error)
});
}
}
}
}
</script>

<style>
.btn-success {
margin-right: 10px;
}
</style>

La fonction data() sert à créer des variables réactives qui seront utilisé dans votre application Vue.
Chaque fois qu'une variable réactive est modifié, si elle est affiché ou utilisé dans votre page, Vue la
mettra à jour immédiatement.

Pour afficher une variable réactive ou une expression dans votre page vous devez utiliser les doubles
crochets Vue remplacera le contenu de l'expression par sa valeur {{ titre }}

La directive v-if permet d'effectuer le rendu ou pas du bloc si l'expression associée à cette directive est
vraie. Par ailleurs comme tout bloc de condition, v-if peut s'utiliser avec v-else-if (où une autre
expression peut être évaluée) v-else pour le bloc par défaut si aucune expression n'est satisfaite.

Lorsque le contenu de l’image ne contient pas un point (indiquant qu’il y a une extension) ce n’est pas
la peine de faire l’affichage de l’image. On pourrait enrichir ce test en ajoutant des validatins sur les
extensions des images.

v-bind Permet d'assigner une expression à un attribut. Vue va remplacer l'expression par sa valeur (ex:
image_url : http://www.exemple.com/car.jpg <img v-bind:src="image_url" /> ou syntaxe raccourci
<img :src="image_url" />

Vue permet de gérer les événements javascript comme click, input, change, etc. Pour ce faire vous
devez utiliser la directive v-on: suivit du nom de l'évènement.

v-on:click Permet d'exécuter du code sur le click d'un élément

<button v-on:click="deleteLivre(liv.id)">Delete</button>

ou syntaxe raccourci

<button @click="deleteLivre(liv.id)">Delete</button>

La méthode appelée (deleteLivre ) est développée dans la partie methods dans le script.

created est appelé de manière synchrone après la création de l'instance. A ce stade, l'instance a fini de
traiter les options, ce qui signifie que les éléments suivants ont été configurés : observation des
données, propriétés calculées, méthodes, rappels watch/event. Cependant, la phase de montage n'a
pas encore commencé et la propriété $el ne sera pas encore disponible.
Une autre alternative est mounted qui est appelé après que l'instance vient d'être montée mais ce
hook n'est pas appelé lors du rendu côté serveur.

ProductService est appelée pour faire appel à la méthode getAll ayant l’axios de get.

Résultat obtenu :

15. Création du formulaire d’ajout

La méthode de post Axios prend l'API REST et envoie la requête POST au serveur. Il crée les données
des livres que nous ajoutons dans JSON database.

Ajoutez le code ci-dessous dans le fichier components/CreateComponent.vue.

<template>
<div class="row justify-content-center">
<div class="col-md-6">
<h3 class="text-center">Create Student</h3>
<form @submit.prevent="handleSubmitForm">
<div class="form-group">
<label>ISBN</label>
<input type="text" class="form-control" v-
model="livre.isbn" required>
</div>

<div class="form-group">
<label>Titre</label>
<input type="text" class="form-control" v-
model="livre.titre" required>
</div>

<div class="form-group">
<label>Edition</label>
<input type="text" class="form-control" v-
model="livre.maisonedition" >
</div>

<div class="form-group">
<label>Année</label>
<input type="number" class="form-control" v-
model="livre.annedition" >
</div>

<div class="form-group">
<label>Auteur</label>
<input type="text" class="form-control" v-
model="livre.auteur" >
</div>

<div class="form-group">
<label>Prix</label>
<input type="number" class="form-control" v-
model="livre.prix" >
</div>

<div class="form-group">
<label>Quantité</label>
<input type="number" class="form-control" v-
model="livre.qtestock" >
</div>

<div class="form-group">
<label>Catégorie</label>
<input type="text" class="form-control" v-
model="livre.categorie" >
</div>

<div class="form-group">
<label>Image</label>
<input type="file" class="form-
control" @change="onFileChange">
</div>

<div class="form-group">
<button class="btn btn-danger btn-block">Ajouter</button>
</div>
</form>
</div>
</div>
</template>

<script>
import ProductService from "../services/LivreService";

export default {
data() {
return {
livre: {
isbn: "",
titre: "",
maisonedition: "",
annedition: "",
auteur: "",
prix: "",
qtestock: "",
categorie: "",
image: ""
}
}
},
methods: {
handleSubmitForm() {
ProductService.add(this.livre).then(() => {
this.$router.push('/')
this.livre = {
isbn: "",
titre: "",
maisonedition: "",
annedition: "",
auteur: "",
prix: "",
qtestock: "",
categorie: "",
image: ""
}
}).catch(error => {
console.log(error)
});
},
onFileChange(e) {
this.livre.image = e.target.files[0].name;
}
}
}
</script>

<style scoped>
img {
width: 30%;
margin: auto;
display: block;
margin-bottom: 10px;
}
</style>

v-model permet de lier la valeur d'un champs de saisie avec une variable. Si vous avez modifié l'un ou
l'autre Vue mettra à jour automatiquement l'autre. Du coup, la variable et le champ de saisie auront
toujours la même valeur. Il s’agit du databiding.

La méthode onFileChange permet de récupérer le contenu du champ file correspondant à l’image


sélectionnée. Puisque le databiding ne marche pas avec ce type file.

Résultat obtenu :

16. Formulaire de modification

Ajoutez le code suivant dans le fichier components/EditComponent.vue.

<template>
<div class="row justify-content-center">
<div class="col-md-6">
<h3 class="text-center">Create Student</h3>
<form @submit.prevent="handleSubmitForm">
<div class="form-group">
<label>ISBN</label>
<input type="text" class="form-control" v-
model="livre.isbn" required>
</div>

<div class="form-group">
<label>Titre</label>
<input type="text" class="form-control" v-
model="livre.titre" required>
</div>

<div class="form-group">
<label>Edition</label>
<input type="text" class="form-control" v-
model="livre.maisonedition" >
</div>

<div class="form-group">
<label>Année</label>
<input type="number" class="form-control" v-
model="livre.annedition" >
</div>

<div class="form-group">
<label>Auteur</label>
<input type="text" class="form-control" v-
model="livre.auteur" >
</div>

<div class="form-group">
<label>Prix</label>
<input type="number" class="form-control" v-
model="livre.prix" >
</div>

<div class="form-group">
<label>Quantité</label>
<input type="number" class="form-control" v-
model="livre.qtestock" >
</div>

<div class="form-group">
<label>Catégorie</label>
<input type="text" class="form-control" v-
model="livre.categorie" >
</div>

<div class="form-group">
<label>Image</label>
<input type="file" class="form-
control" @change="onFileChange">
</div>

<div class="form-group">
<button class="btn btn-danger btn-block">Modifier</button>
</div>
</form>
</div>
</div>
</template>

<script>
import ProductService from "../services/LivreService";

export default {
data() {
return {
livre: {}
}
},
created() {

ProductService.getOne(this.$route.params.id).then((res) => {
this.livre = res.data;
})
},
methods: {
handleSubmitForm() {

ProductService.edit(this.$route.params.id, this.livre).then(()
=> {
this.$router.push('/')
this.livre = {
isbn: "",
titre: "",
maisonedition: "",
annedition: "",
auteur: "",
prix: "",
qtestock: "",
categorie: "",
image: ""
}
}).catch(error => {
console.log(error)
});
},
onFileChange(e) {
this.livre.image = e.target.files[0].name;
}
}
}
</script>

<style scoped>
img {
width: 30%;
margin: auto;
display: block;
margin-bottom: 10px;
}
</style>

Ici, nous devons faire face à deux choses, et nous devons rendre les données lorsque l'utilisateur
atterrit sur le composant des détails de l'étudiant et faire la demande de publication pour mettre à
jour les informations sur le serveur.

Pour obtenir l'identifiant actuel à partir de l'URL existante, utilisez this.$route.params.id vue API.

En utilisant la même API, nous pouvons obtenir l'identifiant de l'URL et mettre à jour les valeurs de la
base de données en utilisant l'API.

$route / this.$route est un object global qui contient des informations sur la route actuelle:

- name
- fullPath
- path
- query
- params

Résultat obtenu :

Vous aimerez peut-être aussi