---
# System prepended metadata

title: VueJS Workshop session 1 (02.11.2020)
tags: [workshop, vuejs, hearc, devweb]

---

###### tags: `vuejs` `workshop` `devweb` `hearc`

# VueJS Workshop session 1 (02.11.2020)

# 1. Introduction

## Github base project

https://github.com/SpicyPaper/workshop-vuejs-simple-demo

HTTPS
```git
git clone https://github.com/SpicyPaper/workshop-vuejs-simple-demo.git
```

SSH
```git
git clone git@github.com:SpicyPaper/workshop-vuejs-simple-demo.git
```


## Vue Devtools

Installer Vue Devtools à partir d'ici : https://github.com/vuejs/vue-devtools#vue-devtools

Vue Devtools permet de visualiser la structure et les données de l'application.
Se qu'il se passe dans l'application et dans chaque composants.
> Sur Chorme il faudra peut être cocher la case "Allow access to file URLs"

## ES6

Si VSCode est utilisé installer `es6-string-html`, nous en aurons besoin plus tard.

## CDN Vue

Copier coller le CDN Vue sur la page de Vue 2 dans la balise head de l'html, nous utiliserons un version précise, donc voici le CDN pour cette version.

```html
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
```

# 2. Creating the Vue App

## Init app Vue

Dans l'html avoir un div avec `id="app"`.
Et donc dans `main.js` on peut créer notre application Vue.

```js
var app = new Vue({})
```

## Expression {{}}

Ajoutons quelques éléments à notre app Vue.
Ajoutons un titre (h1) à notre application à l'aide de Vue.
Il faut donc créer une variable Vue dans data et l'utiliser dans l'html à l'aide de `{{}}`.
> ES6 syntaxe : `data: function() {}` --> `data() {}`

```js
var app = new Vue({
  data() {
    return {
      title: 'Achat de café Nespresso',
    }
  }
})
```

> {{}} interprète se qui se trouve dedans, cela permet d'effectuer des opérations en tout genre (concaténation, opération ternaire, etc...)

Il est possible d'interagir avec Vue depuis la console en écrivant par exemple 

```js
app.title = "Ceci est un titre différent"
```

## Challenge

Ajouter une description avec la même technique que pour le titre, une expression dans un élément `p` sous `h1`.

# 3. Attribute Binding

v-bind permet de lier un attribut html à une expression.
Exemple de syntaxe : `v-bind:src`, `v-bind:class`, `v-bind:disabled`

Ajoutons une image grâce à ce concept.
Il faut créer une nouvelle var dans data et ensuite l'utiliser dans l'html.

```html
<img v-bind:src="image">
```

> Raccourci pour v-bind : "v-bind:src" --> ":src"

## Challenge

Ajouter un lien sur le titre en utilisant le binding et `href`.

# 4. Conditional Rendering

## v-if et v-else
`v-if` et `v-else` permettent d'afficher des choses différentes en fonction de la condition

Ajoutons un booléen dans data `inStock` et utilisons le pour afficher un message différent à l'utilisateur en fonction de sa valeur.

```html
<p v-if="inStock">Disponible</p>
<p v-else>Plus de stock</p>
```

## v-else-if

Il est possible d'avoir des conditions plus complexes en utilisant aussi `v-else-if`.

```html
<p v-if="stock > 10">Disponible</p>
<p v-else-if="stock <= 10 && stock > 0">Peu de stock</p>
<p v-else>Plus de stock</p>
```

## v-show

`v-show` utilise la visibilité de l'élément, il est de se fait très utile et recommandé lorsque l'on désire afficher et masquer fréquemment des éléments du DOM.

## Challenge

Ajouter une propriété `onSale` permettant d'afficher "En Vente !".

# 5. List Rendering

`v-for` peut s'avérer très utile lorsque l'on désire afficher une liste d'éléments.

```
v-for="item in collection"
```

## Tableaux simples

Commençons par afficher une liste de détails à notre café.
Il faut donc créer un tableau d'élément dans data.

```js
details: [ 'Doux', 'Harmonieux' ]
```

Puis l'utiliser dans l'html.
```html
<ul>
  <li v-for="detail in details">
    {{ detail }}
  </li>
</ul>
```

## :key

Il est recommandé de donner une `:key` pour chaque élément de la liste, cela permet de donner un id unique à chaque élément du DOM et permet ainsi à Vue de suivre tous les éléments lorsque le DOM est modifié. Le résultat est l'améliorer des performances et cela peut s'avérer très utile par la suite, lors de l'utilisation des animations. Autant appliquer la bonne pratique dès le départ.

Il faut donc créer des tableau d'objets.
Créons un nouveau tableau contenant des textes avec un id dans data.
```js
carouselImages: [
  {
    id: 1,
    text: 'Capsule 1',
  },
  {
    id: 2,
    text: 'Capsule 2',
  },
  {
    id: 3,
    text: 'Tasse',
  },
  {
    id: 4,
    text: 'Paquet',
  }
],
```

Il faut maintenant afficher notre tableau dans l'html avec l'attribut `:key`.

```html
<div v-for="carouselImage in carouselImages" :key="carouselImage.id">
  {{ carouselImage.text }}
</div>
```

## Challenge

Ajouter un tableau de taille de paquet contenant la quantité de capsules dans un paquet (id, quantity, price) et afficher toutes ces infos à l'utilisateur en utilisant `v-for` et `:key`.

# 6. Event Handeling

Nous allons maintenant voir comment gérer les événements avec Vue grâce à la directive `v-on`.

## Exemple simple

Faisons un exemple en ajoutant un système de panier à notre site.

Commençons par ajouter un bouton permettant d'ajouter des éléments dans notre panier.

Il faut ajouter une var `cart` dans data qui contiendra la valeur actuelle de notre panier.
Puis ajouter un bouton dans l'html en y ajoutant la directive `v-on` et en incrémentant le panier de 1 à chaque clique.
```html
<button v-on:click="cart += 1">
  Ajouter au panier
</button>
```
> Il existe une syntaxe plus courte pour `v-on`, il s'agit du `@` donc par exemple `v-on:click` donnera `@click`

Ici nous avons effectué l'opération directement dans l'html car notre opération est simple. Dans le cas ou nous souhaitons effectué plusieurs actions il est largement préférable d'utiliser des méthodes. Cela tombe bien car Vue permet de faire cela.

## methods

Pour se faire ajoutons l'élément `methods` à notre app Vue dans notre code JS au même niveau que data.

```js
data() {
},
methods: {
  method1: function() {
  },
  method2: function() {
  }
}
```

Il est maintenant possible d'ajouter une nouvelle méthode afin de pouvoir ensuite l'utiliser dans l'html.

```js
methods: {
  addToCart: function() {
    this.cart += 1
  },
```

> `this.cart` fait référence à la var `cart` dans data
> Les méthodes peuvent également être écrite comme ceci : `addToCart: function() {}` --> `addToCart() {}`

## Carrousel

Ce qui pourrait être vraiment sympa c'est de faire un carrousel pour montrer plusieurs images du café à l'utilisateur.

Nous allons utiliser le tableau d'objet que nous avons créé précédemment `carouelImages`. Il faut ajouter un attribut `image` à chaque objet qui contiendra le lien vers une image dans notre dossier images.

```js
carouselImages: [
  {
    id: 1,
    text: 'Capsule 1',
    image: './images/colombia.png',
  },
  {
    id:  2,
    text: 'Capsule 2',
    image: './images/colombia_de_cote.png',
  },
  {
    id: 3,
    text: 'Tasse',
    image: './images/colombia_tasse.png',
  },
  {
    id: 4,
    text: 'Paquet',
    image: './images/colombia_paquet.png',
  }
],
```

Ensuite nous pouvons modifier notre html comme ceci afin d'afficher une image en dessous de l'image principale. Il ne nous reste plus qu'à ajouter la directive `@mouseover` et la relier à une méthode `updateImage` dans data qui va changer la valeur de la var `image`

```html
<div>
  <span v-for="carouselImage in carouselImages"
    :key="carouselImage.id"
    @mouseover="updateImage(carouselImage.image)">
    <img height="50"
      alt="carouselImage.text"
      :src="carouselImage.image">
  </span>
</div>
```

Il est possible d'utiliser d'autre événement comme `change` sur des radios p. ex.

## Challenge

Créer un nouveau bouton et une nouvelle méthode pour décrémenter le nombre d'objet dans le panier.

# 7. Class & Style Binding

Nous allons voir comment Vue permet d'effectuer des actions sur les styles et les classes.

## :style

Changeons la couleur des détails du café.

Il faut commencer par adapter le tableau `details` dans data pour répondre à nos nouveaux besoin et profitons-en pour lui donner un attribut id.

```js
details: [
  {
    id: 1,
    text: 'Doux',
    color: '#6C99C6'
  },
  {
    id: 2,
    text: 'Harmonieux',
    color: '#BF9E74'
  }
],
```

Dans l'html il faut donc adapter son utilisation.
Pour se qui est de clé, ce n'est pas nouveau et il faut également adapter l'utilisation de l'affichage du texte en appelant la propriété de l'objet.
Au niveau du style il suffit d'utiliser `:style` en utilisant l'attribut `color` de `detail` et en le liant à l'attribut css `color`.

```html
<ul>
  <li v-for="detail in details"
    :key="detail.id"
    :style="{ color: detail.color }">
    {{ detail.text }}
  </li>
</ul>
```

## camel vs kebab

Il y a 2 manières possible d'utiliser les attributs css
1. En notation camelCase `:style="{ backgroundColor: detail.color }"` ou
2. En notation 'kebab-case' `:style="{ 'background-color': detail.color }"`

## Objet de style

Il est également possible d'utiliser un objet de style, changeons le style du bouton d'ajout au panier pour illustrer l'exemple :

Dans le JS on crée un objet qui va regrouper tous nos style.
```js
styles: {
  roundButton: {
    borderRadius: "20px",
    padding: "10px",
    backgroundColor: "rgb(0, 114, 180)",
    color: "white",
    cursor: "pointer"
  }
},
```

Dans l'html on ajoute `:style` au bouton. Mais cette fois il suffit d'ajouter notre objet avec un notation bien plus simple car tous les styles sont déjà contenu dans l'objet JS déjà correctement formaté.
```html
<button
  @click="addToCart"
  :style="styles.roundButton">
  Ajouter au panier
</button>
```

## :class

Essayons de voir la différence si on utilise les classes css.

Désactivons les interactions avec notre bouton si le stock est <= 0 en utilisant l'attribut `disabled`.
```html
<button
  @click="addToCart"
  :style="styles.roundButton"
  :disabled="stock <= 0">
  Ajouter au panier
</button>
```

Rendons le tout un peu plus clair visuellement en ajoutant du css. Ne pas oublier `!important` sur nos attributs css, car nous modifions dans une classe le style ajouté depuis l'élément html.
```css
.disabledButton {
  background-color: #d8d8d8 !important;
  cursor: not-allowed !important;
}
```

> Il est possible d'utiliser l'attribut `class` et `:class` sur le même élément html, les classes vont être fusionné

## Opérateur ternaire [ ? : ]

Il est également possible d'effectuer des opérations ternaires. Modifions le style du texte indiquant combien de 
```html
<div :class="[cart > 0 ? 'cartFilled' : '']">
  Panier({{ cart }})
</div>
```

## Challenge

Changer l'opacité de l'image principale à l'aide d'une classe et lorsqu'il n'y à plus de stock.

# 8. Computed Properties

Vue permet de créer des propriétés calculées.

## Cache

Cela présente des avantages, comme le fait que les propriétés calculées sont mises en cachent. Cela veut dire que la propriété est "calculé" une seule fois et ensuite simplement réutilisé (optimisation de la part de Vue), si un élément de cette propriété à changé alors la propriété est calculé à nouveau puis remise en cache.

## Exemple simple avec le titre

Afin de tester cette nouvelle notion nous allons couper le contenu de notre variable `title` en 2 dans data.
```js
order:  'Commander du café',
brand:  'Nespresso',
```

Mais souhaitons continuer d'utiliser la var `title` dans l'html afin de pouvoir utiliser title, order ou brand quand cela est nécessaire.
Nous allons donc créer un propriété calculée et pour se faire il faut ajouter le terme `computed` au même niveau que data et methods dans le JS.
Ensuite nous pouvons créer notre propriété calculée que nous allons nommé `title` afin que son fonctionnement reste identique ou nous l'avions utilisé précédemment.

```js
data() { ... },
methods: { ... },
computed: {
  title() {
    return this.order + ' ' + this.brand
  }
}
```

## Amélioration du carrousel

Maintenant nous allons simplifier et mettre à profit notre apprentissage des propriétés.
Supprimons la var `image = 'url'` dans data et remplaçons la par `selectedImage = 0` qui sera un index pointant sur l'image actuellement sélectionné de notre carrousel.

Ensuite modifions l'appel de la méthode pour mettre cette variable à jour. D'abord dans la boucle for du carrousel ajoutons un index comme ceci `v-for="(carouselImage, index) in carouselImages"`. Puis l'appel à la méthode `@mouseover="updateSelectedImage(index)"` et la méthode dans le JS `updateSelectedImage(index) { this.selectedImage = index }`.
Et pour finir créons une nouvelle propriété calculée afin de remplacer la variable image d'avant `image() { return this.carouselImages[this.selectedImage].image }`.

## Challenge

Remplacer tous les endroits ou nous avons utilisé `stock <= 0` par un propriété calculée. (Attention au condition qui risque de s'inverser dans certain des cas)
