TP VueJS
===
## Objectif de ce TP
- Comprendre la notion de composant en VueJS,
- Utilisation de typescript pour structurer vos développements
- Comprendre le fonctionnement basique du routeur Vue
- Bien voir les analogies de concepts entre Angular et Vue
## Create a project using vue-cli
:warning: **Utiliser nodeJS au moins en version 16**
**Create your app**
```bash
mkdir tpWeVue
cd tpWeVue
npm create vue@latest
```

Let the default choices for other choices.
```bash
cd tp-web-vue
npm install
code . &
npm run format
npm run dev
```
Avant de faire nos propres composants, observons le projet généré.
## Anatomie du projet généré
Chaque composant vient avec un fichier en extension *.vue*. On utilise par défaut en vue 3 l'APi composition. Chaque composant a au sein de ce fichier trois partie, la partie CSS, la partie template et la partie modèle en TS.
De base le projet généré vient avec un composant de base **App**. Ce composant contient une directive *router-view* *l26* au sein de son template
```html
<router-view/>
```
Cela correspond l'utilisation du router, cela indique que le composant enfant à instantier et afficher dépend de la route avec laquelle on arrive sur l'application.
Si l'on regarde la partie typescript du router (fichier router/index.ts)
```ts
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView,
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('../views/AboutView.vue'),
},
],
})
export default router
```
On voit que quand on arrive à la racine de l'application c'est le composant **HomeView** qui est chargé. Ce composant est défini dans le fichier HomeView.vue
```html
<script setup lang="ts">
import TheWelcome from '../components/TheWelcome.vue'
</script>
<template>
<main>
<TheWelcome />
</main>
</template>
```
Ce composant a lui aussi un composant fils qui est istancié dans son template. Le composant **TheWelcome**.
## Un tour d'horizon sur la partie devtools
En allant sur la partie devtools http://localhost:5173/__devtools__/
Vous pouvez avoir accès à une vue globale de la structure de votre application.
## Comprendre la notion de directive
- Utilisation des directives.
Simplifions le code du composant TheWelcome.
```htmlmixed=
<script setup lang="ts">
import { ref } from 'vue'
const visible = ref(true)
const title = ref("WE")
function foo() {
visible.value = !visible.value
}
</script>
<template>
<h1>hello</h1>
<p v-if="visible">Maintenant vous me voyez {{ title }}</p>
<button v-on:click="foo()">ok</button>
</template>
```
Nous avons supprimer l'instantiation du sous composant, nous avons ajouter une balise **p** avec une directive *v-if* afin d'afficher la valeur du paragraphe si l'attribut du composant visible était vrai. Nous avons utiliser la valeur de l'attrribut title afin de montrer le mapping MVVM entre l'objet associé à ce composant et le template de vue. Enfin, nous montrons l'utilisation de la directive v-on permettant de lier des èvénement du dom à l'appel d'une méthode sur un objet instance associé à ce composant).
Jusque là si tout va bien, vous devez vous dire chouette, cela ressemble bcp à Angular. C'est le cas pour le modèle de composant.
- Définir ses propres directives.
En s'inspirant de la documentation des custom directives de vuejs.
https://vuejs.org/guide/reusability/custom-directives.html
Créer une directive pour changer le background color d'une **\<div\>** qui contient un texte.
Votre directive pourra avoir une couleur par défaut. Par exemple la couleur par défaut sera : yellow,
Votre directive pourra aussi avoir comme argument la couleur de votre choix (dans le composant textComponent.vue un jeu de couleur est déjà renseigné dans l'objet data).
Vous pourrez également remplacer le texte de votre div par Mon texte est de couleur : la couleur que j'ai passé en arguments à ma directive.
Vous devez obtenir une directive proche de celle-là.
Dans le fichier main.ts, vous pouvez facilement ajouter vos propres directives. Votre fichier *main.ts* ressemblera à cela:
```ts
import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
const defaultBackgroundColor = 'lightBlue'
const defaultText = 'blue'
app.directive('background', (el, binding) => {
console.log(binding.arg) // => "white"
el.style.backgroundColor = binding.arg || defaultBackgroundColor
el.innerHTML = 'My background text is : ' + binding.arg || defaultBackgroundColor
});
```
à l'usage au sein du composant **Home**, cela donnera ceci.
```html
<script setup lang="ts">
import { ref } from 'vue'
const visible = ref(true)
const title = ref("WE")
function foo() {
visible.value = !visible.value
}
</script>
<template>
<div class="home">
<h1>hello</h1>
<p v-if="visible">Maintenant vous me voyez {{ title }}</p>
<button v-on:click="foo()">ok</button>
<div v-background>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore
et dolore magna aliqua</div>
<div v-background:green>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua</div>
</div>
</template>
```
## Comprendre la notion de composant Web
1. Créer un composant **todos** et afficher un titre H1 qui aura pour titre Todos.
- Create a file Todos.vue
- Ajouter une section template
2. Instantier ce composant dans le composant **Home**.
2. Le but de ce composant est d'afficher une liste de tâches. Il est donc nécessaire de créer encore un autre composant TODOComponent dont le but est de gérer l'affichage des données d'une tâche (à savoir au minimum, l'intitulé et l'état mais il sera aussi possible d'ajouter une date d'échéance). Nous crérons aussi une classe métier TODO pour représenter les données d'une tâche. Vous pourrez instantier votre composant dans un *v-for* (https://vuejs.org/guide/essentials/list.html).
3. Fonctionnalité *ajouter un nouvelle tâche*. Dans le composant todos, créer un input et un bouton pour créer une tâche. La tâche sera par défaut à un état *à faire*. Attention quand vous modifiez une liste, il est nécessaire de passer par les méthodes de mutations (https://vuejs.org/guide/essentials/list.html#array-change-detection) pour que la modification soit prise en compte dans le *v-for* qui permet d'afficher les différentes tâches à faire.
4. Dans le composant **todos**, créer un footer et ajouter un span pour savoir le nombre de tâches qu’il reste à faire.
5. Mettre en place les filtres, toutes les tâches, les tâches à faire, les tâches faites. [doc](https://vuejs.org/guide/essentials/list.html#displaying-filtered-sorted-results).
6. Supprimer toutes les tâches.
7. Supprimer une tâche en particulier.
8. Afficher le footer que si il y a au moins un todo.
8. Ajouter un bouton pour supprimer les tâches terminées.
9. Editer le nom d’une tâche quand on double click sur un intitulé d'une tâche.
11. Au blur (évènement JS quand on perd le focus), arrêter d’éditer le champs.
L'idée est d'avoir au minimum à la fin de ces éléments un composants todos réutilisable. Ce dernier pourra soit contenir tout le code html soit réutilisé un autre composant eprmettant de gérer l'affichage et la modification des données d'une tâche.
## Consommer un service REST
Contrairement à Angular, VueJS n'impose pas un service particulier pour consommer des API Rest. Il n'impose pas de mécanisme d'injection de dépendances, ...
Pour consommer des APIs Rest depuis une application React ou Vue, on utilise assez souvent Axios pour consommer des services REST.
https://www.bezkoder.com/vue-3-typescript-axios/
Vous pouvez utiliser une API fictive pour initialiser votre liste de TODOs.