Open menu

Préambule

  • L'objectif principal de ce TP est de reprendre le TP n°1 en manipulant les principes de props et d'événements, au travers de la création de nouveaux composants "outils"

  

1°/ Une liste avec cases à cocher

1.1°/ objectifs et contraintes

  • L'objectif est de créer un composant permettant d'afficher une liste verticale d'objets JSON de même type, mais en limitant l'affichage à certains champs de ces objets.
  • Chaque item de la liste peut être (de façon optionnelle) :
    • précédé par une case à cocher,
    • suivie par un bouton.
  • Enfin, la liste est suivie par un bouton optionnel.

 

  • Pour cela, le composant doit avoir comme props :
    • data : un tableau d'objets de même type,
    • fields : un tableau donnant le nom des champs du tableau qu'il faut afficher,
    • itemChecked : un booléen qui indique s'il faut une case à cocher devant les items,
    • checked : un tableau de booléens qui indique si une case est cochée ou non,
    • itemButton : un objet au format { show: true/false, text: '....' }. Le booléen indique s'il faut un bouton après les items, et les ... sont le texte de ces boutons.
    • listButton : un objet au format { show: true/false, text: '....' }. Le booléen indique s'il faut un bouton après la liste, et les ... sont le texte de ce bouton.

 

  • Par exemple, prenons le tableau JSON suivant :
[
  {nom:"dupond", prenom:"jean",age:31},
  {nom:"durand", prenom:"pierre",age:35}
]
  • Si on donne ce tableau en entrée au composant, ainsi que le tableau [ 'prenom', 'nom' ] représentant le nom des champs à afficher, alors le composant doit afficher (+ si demandé les cases à cocher et boutons)  :
jean dupond
pierre durant

 


Rappel javascript : on peut accéder aux champs d'un objet grâce à la notation obj['nom_champ']. Par exemple, si j'ai une variable e contenant le premier objet du tableau d'exemple ci-dessus, alors e['nom'] contient 'dupond'.


1.2°/ Mise en place

  • Créer un composant CheckedList avec dedans :
<template>
  <div>
  </div>
</template>

<script>

export default {
  name: 'CheckedList',
  props: {
    data: Array, // les données sources
    fields: Array, // le tableau contenant le nom des champs
    itemCheck: Boolean, // s'il y a des case à cocher
    checked: Array, // le tableau des cases cochées
    itemButton: Object, // l'objet pour les boutons d'items
    listButton: Object, // l'objet pour le bouton de liste
  },
  data : () => {
    return {
    }
  }
}
</script>

<style scoped>
</style>

 

Modifier la partie <template> pour que :

  • le composant affiche sous forme de liste verticale (à vous de choisir l'apparence : paragraphes, liste à puce, table, ...) les objets de la props data. Pour chaque objet, seuls ses propriétés indiquées dans la props fields doivent être affichées (NB : dans l'ordre d'apparition dans fields).
  • si la props itemCheck vaut true, chaque ligne de la liste doit commencer par une case à cocher. La ième case doit être cochée si checked[i] vaut true.
  • si la props itemButton.show vaut true, chaque ligne doit se terminer par un bouton, dont le contenu est indiqué par itemButton.text
  • si la props listButton.show vaut true, un bouton doit apparaître après la liste, dont le contenu est indiqué par listButton.text

En cas d'interaction utilisateur avec les cases et les boutons :

  • chaque fois que l'état d'une case est changé, le composant doit émettre un événement checked-changed, avec comme valeur l'indice de la case à cocher (c.a.d. celui de la ligne)
  • chaque fois qu'un bouton de fin de ligne est pressé, le composant doit émettre un événement item-button-clicked, avec comme valeur l'indice du bouton (c.a.d. celui de la ligne)
  • chaque fois que le bouton après la liste est pressé, le composant doit émettre un événement list-button-clicked.

 

1.3°/ Tests

  • Modifier PersosView pour que la liste des items achetés soit affichées grâce au composant CheckedList :
    • pour chaque item acheté, une ligne de CheckedList doit afficher son nom et son type,
    • chaque ligne doit commencer par une case à cocher et se terminer par un bouton,
    • la liste des lignes doit être suivi d'une bouton.
  • Quand l'utilisateur clique sur un bouton de fin de ligne, une boîte de dialogue apparaît (cf. méthode alert() de JS) avec un message indiquant le nom et le prix de l'item.
  • Quand l'utilisateur clique sur le bouton d'après liste, une boîte de dialogue apparaît avec un message indiquant le nom de tous les items dont la case est cochée.

Remarques :

  • La liste des items achetés est un tableau d'objets Item. On peut donc utiliser ce tableau directement comme valeur de la props data de CheckedList
  • La props checked doit avoir comme valeur un tableau de booléen, fourni par PersosView. Le problème, c'est que le nombre d'items achetés peut varier. On ne peut donc pas initialiser ce tableau avec une suite de valeurs à false, car il faudrait connaître le nombre de ces valeurs, c.a.d. le nombre actuel d'items achetés. La solution consiste à créer dans PersosView un tableau des indices des items sélectionnés et de créer une fonction computed qui va renvoyer un tableau de booléens initialisé grâce au tableau d'indices. Il y a autant de booléens qu'il y a d'items achetés et la valeur du ième élément est true uniquement si i se trouve dans le tableau des indices. C'est donc ce tableau de booléens qui est fourni en props à CheckedList. Quand PersosView capture un événement checked-changed, il met à jour le tableau des indices, ce qui provoque le recalcul du tableau de booléens.
  • Pour les 2 autres événements à capturer, il est conseillé d'ajouter des fonctions dans methods.

 

2°/ La barre de navigation

2.1°/ Objectifs et contraintes

  • Dans le TP n°1, le changement d'affichage entre les composants TownsView et PersosView est fait en changeant l'URL dans le navigateur.
  • L'objectif de cet exercice est de créer une barre de navigation sous la forme d'un composant réutilisable.
  • Pour le réaliser, il y a 2 options :
    • soit c'est la barre de navigation qui permet elle-même de suivre une route,
    • soit la barre émet un événement et le composant utilise la valeur de l'événement pour décider quoi faire, en l'occurrence quelle route prendre.
  • L'avantage de la 2ème solution est qu'elle découple totalement la barre de navigation du fait que l'on utilise ou non vue-router. D'un point de vue composition de composants, c'est donc mieux.

 

2.2°/ Mise en place

  • Créer un composant NavBar.vue et copier/coller dedans le code suivant :
<template>
  <div>
  // button list, values/colors from props titles.
  </div>
</template>

<script>
export default {
  name: 'NavBar',
  props: { titles: Array }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
  • La props titles (dont la valeur est fournie par le composant parent) est un tableau d'objet au format suivant :
[ {text: "menu1", color: "color1} , {text: "menu2", color: "color2}, ... ]

 

  • Pour créer la liste de boutons dans la partie template, on utilise la balise <button> ... texte ... </button>
  • Il doit y avoir autant de boutons qu'il y a d'objets dans la props titles et leur texte et couleur sont donnés par les champs text et color (comme dans le TP 0)
  • Quand on clique sur le bouton n° X, on doit émettre l'événement menu-clicked avec comme valeur X. Ainsi, le composant parent recevra la valeur 0 quand on clique sur le premier bouton, 1 sur le deuxième, etc.

 

2.3°/ Test

  • Modifier App.vue  :
    • enlever tout ce qui se trouve dans la balise <v-app-bar> et ajouter une instance du composant NavBar,
    • donner en props à cette instance un objet adéquat, afin d'afficher 2 boutons, dont le texte est "Personnages" et "Ville", la couleur étant libre.
    • capturer l'événement menu-clicked et appeler une fonction dans methods avec en paramètre la valeur de l'événement (donc 0 ou 1 si vous avez correctement codé ce qui précède)
    • cette fonction permet de suivre la route persos ou bien towns, ce qui va provoquer l'affichage soit du composant PersosView, soit de TownsView

Remarques :

 

3°/ Sélection et affichage d'une boutique

3.1°/ Objectifs et contraintes

  • L'objectif est de modifier TownsView pour pouvoir sélectionner une boutique, et créer un composant ShopDetails, permettant d'afficher ce que propose une boutique, donc la liste des items en stock et ceux sur commande.
  • Dans les deux cas, on va utiliser le composant CheckedList.
  • Le composant ShopDetails doit afficher quelque chose du genre (NB : les textes entre [ ]  sont des boutons) :
Patty Smith
Stock : 3 items Sur commande : 1 item

 ⃞ conic helmet : 200 po  [ achat ]

 ⃞ dagger : 100 po [ achat ]

 ⃞ wine : 2 po [ achat ]

[ Acheter sélectionnés ]

chicken : 10 po [ commande ]

 

3.2°/ Mise en place

  • Modifier TownsView pour que la liste des boutiques d'une rue soit affichée grâce à un composant CheckedList.
  • Chaque ligne de ces listes doit afficher le nom de la boutique puis un bouton intitulé "Sélectionner" (pas de cases à cocher, ni de bouton en fin de liste)
  • Quand on clique sur un tel bouton, un composant Shop doit apparaître sous le tableau, avec les données associées à la boutique choisie. Si on clique sur un autre bouton, il faut que le contenu de Shop change pour afficher les données de la nouvelle boutique choisie.
  • Cela implique notamment qu'il faut que TownsView ait une variable référençant la boutique courante (NB : on verra plus tard que cette variable sera mieux dans le store), afin de la passer en props au composant Shop.

 

  • Créer le composant ShopDetails
  • Quand ShopDetails capture les événements émis par les composant CheckedList, appeler des fonctions qui se contentent de mettre un message dans la console. Le traitement réel sera fait après avoir vu en cours le plugin vuex.