Académique Documents
Professionnel Documents
Culture Documents
avec Vue JS 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 backend NodeJs. 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.
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
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.
node app
Articles : http://localhost:3001/api/articles
Catégories : http://localhost:3001/api/categories
Sous Catégories : http://localhost:3001/api/scategories
Sous Catégories pour une catégorie bien déterminée :
http://localhost:3001/api/scategories/cat/
4. 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.
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'))).
createApp(App).use(router).mount('#app')
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.
AjoutProduit.vue
EditProduit.vue
Listproduits.vue
<script>
export default {
data() {
return {
}
}
}
</script>
</div>
Il existe deux composants principaux que Vue Router utilise et que vous devrez apprivoiser pour vos
applications :
Ces deux composants constituent la base de l'utilisation de Vue Router dans nos composants. Ils
facilitent la navigation dans une application Vue.
L'option d'historique lors de la création de l'instance de routeur nous permet de choisir parmi
différents modes d'historique.
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.
<template>
</template>
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>
Maintenant, nous allons afficher les données sous forme d’un tableau à l'aide des classes Bootstrap,
et nous allons faire appel à la requête axios.get() pour restituer les données du serveur à travers
l’adresse de l’api.
<template >
<div>
<h3>Liste des produits</h3>
<table class="table table-striped">
<thead>
<tr>
<th>Référence</th>
<th>Désignation</th>
<th>Marque</th>
<th>Prix d'achat</th>
<th>Prix de vente</th>
<th>Quantité stock</th>
<th>Image</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="p in Produits" :key="p._id">
<td>{{p.reference}}</td>
<td>{{p.designation}}</td>
<td>{{p.marque}}</td>
<td>{{p.prixAchat}}</td>
<td>{{p.prixVente}}</td>
<td>{{p.qtestock}}</td>
<td>
<img :src="require(`../assets/${p.imageartpetitf}`)" alt=""
width="60">
</td>
<td>
<button class="btn btn-block btn-warning"><router-link :to="{name:
'Edit', params: { id: p._id }}">EDIT</router-link> </button>
<button class="btn btn-block btn-danger"
@click="deleteProduct(p._id)">DELETE</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
Produits: []
}
},
created() {
let apiURL = 'http://localhost:3001/api/articles';
axios.get(apiURL).then(res => {
this.Produits = res.data;
}).catch(error => {
console.log(error)
});
},
methods: {
deleteProduct(id){
let apiURL = `http://localhost:3001/api/articles/${id}`;
</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ée ou utilisé dans votre page, Vue la
mettra à jour immédiatement.
Nous pouvons utiliser la directive v-for pour faire le rendu d’une liste d’éléments en nous basant sur
un tableau. La directive v-for utilise une syntaxe spécifique de la forme item in items, où items
représente le tableau source des données et où item est un alias représentant l’élément du tableau en
cours d’itération. Dans notre exemple il s’agit de v-for="p in Produits"
Il est recommandé de fournir une key avec v-for chaque fois que possible, à moins que le contenu itéré
du DOM soit simple ou que vous utilisiez intentionnellement le comportement de base pour un gain
de performance.
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 {{ p.reference }}
À l’intérieur des structures v-for, nous avons un accès complet aux propriétés de la portée parente. v-
for supporte également un second argument optionnel représentant l’index de l’élément courant.
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.
<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.
Résultat obtenu :
10. On va créer le contenu du composant « AjoutProduit.vue ». Ce composant est appelé lorsqu’on
clique sur le lien « Ajout » du menu.
Les listes correspondantes à la catégorie et la sous catégories sont alimentées à partir de la base de
données. La deuxième liste changera en fonction du choix de la catégorie.
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.
<template lang="">
<form @submit.prevent="ajouterproduit">
<div class="form-group">
<input type="text" class="form-control" placeholder="reference" v-
model="reference">
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="designation" v-
model="designation">
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="marque" v-
model="marque">
</div>
<div class="form-group">
<input type="number" class="form-control" placeholder="prixAchat" v-
model="prixAchat">
</div>
<div class="form-group">
<input type="number" class="form-control" placeholder="prixVente" v-
model="prixVente">
</div>
<div class="form-group">
<input type="number" class="form-control" placeholder="qtestock" v-
model="qtestock">
</div>
<div class="form-group">
Catégories<select class="form-control" v-model="categorie"
@change="getscategories($event)" >
<option v-for="c in Categories" :key="c._id"
:value=c._id>{{c.nomcategorie}}</option>
</select>
</div>
<div class="form-group">
Sous Catégories<select class="form-control" v-model="scategorie">
<option v-for="sc in Scategories" :key="sc._id"
:value=sc._id>{{sc.nomscategorie}}</option>
</select>
</div>
<div class="form-group">
<input type="file" class="form-control"
placeholder="Image" @change="onFileChange">
</div>
<button type="submit" class="btn btn-block btn-primary">Ajouter
Produit</button>
</form>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
id:"",
reference: "",
designation: "",
marque: "",
prixAchat: "",
prixVente: "",
qtestock: "",
imageartpetitf: "",
categorie:"",
scategorie:"",
Categories:[],
Scategories:[]
}
},
methods: {
ajouterproduit(){
const pr = {
reference:this.reference,
designation:this.designation,
marque:this.marque,
prixAchat:this.prixAchat,
prixVente:this.prixVente,
qtestock:this.qtestock,
categorieID:this.categorie,
scategorieID:this.scategorie,
imageartpetitf:this.imageartpetitf
}
axios.post("http://localhost:3001/api/articles",pr)
.then(() => {
this.$router.push('/')})
.catch(error => {
this.errorMessage = error.message;
console.error("There was an error!", error);})
},
onFileChange(e) {
this.imageartpetitf = "images/" + e.target.files[0].name;
},
getscategories(event){
let categ=event.target.value;
console.log(categ)
axios.get('http://localhost:3001/api/scategories/cat/'+categ).th
en(res => {
this.Scategories = res.data;
}).catch(error => {
console.log(error)
});
}
},
created() {
axios.get('http://localhost:3001/api/categories').then(res => {
this.Categories = res.data;
}).catch(error => {
console.log(error)
});
},
}
</script>
<style lang="">
</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.
Résultat obtenu :
11. Par la suite on va créer le contenu du composant « EditProduit.vue » qui permettra de mettre
à jour les données dans la base.
<template lang="">
<form @submit.prevent="modifierproduit">
<div class="form-group">
<input type="text" class="form-control" placeholder="reference" v-
model="Produit.reference">
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="designation" v-
model="Produit.designation">
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="marque" v-
model="Produit.marque">
</div>
<div class="form-group">
<input type="number" class="form-control" placeholder="prixAchat" v-
model="Produit.prixAchat">
</div>
<div class="form-group">
<input type="number" class="form-control" placeholder="prixVente" v-
model="Produit.prixVente">
</div>
<div class="form-group">
<input type="number" class="form-control" placeholder="qtestock" v-
model="Produit.qtestock">
</div>
<div class="form-group">
Catégories<select class="form-control" v-model="Produit.categorie"
@change="getscategories($event)" >
<option v-for="c in Categories" :key="c._id"
:value=c._id>{{c.nomcategorie}}</option>
</select>
</div>
<div class="form-group">
Sous Catégories<select class="form-control" v-model="Produit.scategorie">
<option v-for="sc in Scategories" :key="sc._id"
:value=sc._id>{{sc.nomscategorie}}</option>
</select>
</div>
<div class="form-group">
<input type="file" class="form-control"
placeholder="Image" @change="onFileChange">
</div>
<button type="submit" class="btn btn-block btn-primary">Modifier
Produit</button>
</form>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
Categories:[],
Scategories:[],
Produit:{}
}
},
methods: {
modifierproduit(){
let apiURL =
`http://localhost:3001/api/articles/${this.$route.params.id}`;
axios.put(apiURL, this.Produit).then(() => {
this.$router.push('/')})
.catch(error => {
this.errorMessage = error.message;
console.error("There was an error!", error);})
},
onFileChange(e) {
this.Produit.imageartpetitf = "images/" + e.target.files[0].name;
},
getscategories(event){
let categ=event.target.value;
console.log(categ)
axios.get('http://localhost:3001/api/scategories/cat/'+categ).th
en(res => {
this.Scategories = res.data;
}).catch(error => {
console.log(error)
});
}
},
created() {
axios.get('http://localhost:3001/api/categories').then(res => {
this.Categories = res.data;
}).catch(error => {
console.log(error)
});
let apiURL =
`http://localhost:3001/api/articles/${this.$route.params.id}`;
axios.get(apiURL).then((res) => {
this.Produit = res.data;
})
},
}
</script>
<style lang="">
</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.
Utiliser $route dans vos composants crée un couplage fort à la route.
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
Ces propriétés sont injectées dans chacun des composants enfants, en passant l'instance du routeur à
l'application racine de Vue en tant qu'option router.
$route est la Route actuellement active. C'est une propriété en lecture seule et ses propriétés sont
immutables, mais elles restent malgré tout observables
Résultat obtenu :
12. Améliorer l’affichage de la liste avec datatable
a. Installer datatable
npm install --save datatables.net-dt
b. Installer jQuery
npm install jquery --save
<template >
<div>
<h3>Liste des produits</h3>
<table class="table table-striped" id="example">
<thead>
<tr>
<th>Référence</th>
<th>Désignation</th>
<th>Marque</th>
<th>Prix d'achat</th>
<th>Prix de vente</th>
<th>Quantité stock</th>
<th>Image</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="p in Produits" :key="p._id">
<td>{{p.reference}}</td>
<td>{{p.designation}}</td>
<td>{{p.marque}}</td>
<td>{{p.prixAchat}}</td>
<td>{{p.prixVente}}</td>
<td>{{p.qtestock}}</td>
<td>
<img :src="require(`../assets/${p.imageartpetitf}`)" alt=""
width="60">
</td>
<td>
<button class="btn btn-block btn-warning"><router-link :to="{name:
'Edit', params: { id: p._id }}">EDIT</router-link> </button>
<button class="btn btn-block btn-danger"
@click="deleteProduct(p._id)">DELETE</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import axios from "axios";
//Bootstrap and jQuery libraries
import 'bootstrap/dist/css/bootstrap.min.css';
import 'jquery/dist/jquery.min.js';
//Datatable Modules
import "datatables.net-dt/js/dataTables.dataTables"
import "datatables.net-dt/css/jquery.dataTables.min.css"
import $ from 'jquery';
export default {
data() {
return {
Produits: []
}
},
created() {
let apiURL = 'http://localhost:3001/api/articles';
axios.get(apiURL).then(res => {
this.Produits = res.data;
$(function() {$('#example').DataTable();});
}).catch(error => {
console.log(error)
});
},
methods: {
deleteProduct(id){
let apiURL = `http://localhost:3001/api/articles/${id}`;
const indexOfArrayItem = this.Produits.map((e)=> {return e._id
}).indexOf(id);
</style>
Résultat obtenu :