Skip to content
Snippets Groups Projects
Commit 0967689f authored by Thomas Fritsch's avatar Thomas Fritsch
Browse files

maj readme et screenshots

screenshots et gif theme sombre
ajout d'astuces
wording
mise en forme texte
parent 394a724a
No related branches found
No related tags found
No related merge requests found
Showing
with 86 additions and 58 deletions
......@@ -4,7 +4,7 @@
## Sommaire <!-- omit in toc -->
- [A.1. Récupération du projet](#a1-récupération-du-projet)
- [A.3. Lancement de l'application](#a3-lancement-de-lapplication)
- [A.2. Lancement de l'application](#a2-lancement-de-lapplication)
## A.1. Récupération du projet
......@@ -15,8 +15,7 @@ Il va vous servir de base pour ce nouveau TP.
- soit en cliquant sur le bouton `"Créer une divergence"` (_`"Fork"` sur la version anglaise de gitlab_)
- soit en vous rendant directement sur https://gitlab.univ-lille.fr/js/tp3/-/forks/new
Choisissez de placer le fork dans votre profil utilisateur et configurez le repo **en mode "privé"**
(**`Settings`** > **`Visibility, project features, permissions`** > **`Project visibility`**)
Choisissez de placer le fork dans votre profil utilisateur et configurez le repo **en mode "privé"** (**`Settings`** > **`Visibility, project features, permissions`** > **`Project visibility`**)
2. **Ajoutez-votre encadrant de TP en tant que "reporter" pour qu'il ait accès à votre code :**
......@@ -30,16 +29,16 @@ Il va vous servir de base pour ce nouveau TP.
mkdir ~/tps-js
git clone https://gitlab.univ-lille.fr/<votre-username>/tp3.git ~/tps-js/tp3
```
> _**NB :** Comme pour le TP1, ici je clone dans mon dossier `/home/thomas/tps-js/tp3`. **Si vous êtes sous windows faites attention au sens des slashs et au caractère `"~"`** qui représente le dossier de l'utilisateur sur système unix. Si vous êtes sous windows utilisez **Git bash** (qui comprend cette syntaxe) ou si vous tenez vraiment à utiliser **cmd** pensez à adapter !_
> _**NB :** Comme pour le TP1, ici je clone dans mon dossier `/home/thomas/tps-js/tp3`. **Si vous êtes sous windows faites attention au sens des slashs et au caractère `"~"`** qui représente le dossier de l'utilisateur sur système unix : utilisez **Git bash** (qui comprend cette syntaxe) ou si vous tenez vraiment à utiliser **cmd** ou **powershell** pensez à adapter la commande !_
> _**NB2 :** Comme pour le TP1 aussi, si vous préférez **cloner en SSH** pour ne pas avoir à taper votre mot de passe à chaque fois, renseignez votre clé SSH dans votre [compte utilisateur gitlab](https://gitlab.univ-lille.fr/profile/keys) et clonez à partir de cette URL : `git@gitlab-ssh.univ-lille.fr:js/tp3.git`_
> _**NB2 :** Comme pour le TP1 aussi, si vous préférez **cloner en SSH** pour ne pas avoir à taper votre mot de passe à chaque fois que vous clonerez un TP, renseignez votre clé SSH dans votre [compte utilisateur gitlab](https://gitlab.univ-lille.fr/profile/keys) et clonez à partir de cette URL : `git@gitlab-ssh.univ-lille.fr:js/tp1.git`_
4. **Ouvrez le projet dans VSCodium** (pour les différentes façon d'ouvrir le projet relisez les [instructions du TP1](https://gitlab.univ-lille.fr/js/tp1/-/blob/master/A-preparatifs.md#a3-ouvrir-le-projet-dans-vscodium) )
4. **Ouvrez le projet dans VSCodium/VSCode** (pour les différentes façon d'ouvrir le projet relisez les [instructions du TP1](https://gitlab.univ-lille.fr/js/tp1/-/blob/master/A-preparatifs.md#a3-ouvrir-le-projet-dans-vscodium) )
```bash
codium ~/tps-js/tp3
```
5. **Installez les paquets npm nécessaires au projet** notamment le compilateur [Babel](https://babeljs.io).<br>
5. **Installez les paquets npm nécessaires au projet** (_notamment [Babel](https://babeljs.io) et [webpack](https://webpack.js.org/)_). \
Ouvrez un terminal intégré à VSCodium (<kbd>CTRL</kbd>+<kbd>J</kbd> *(PC)* / <kbd>CMD</kbd>+<kbd>J</kbd> *(Mac)*) et tapez juste :
```bash
npm install
......@@ -49,7 +48,7 @@ Il va vous servir de base pour ce nouveau TP.
>
> **Magique !** 🙌
## A.3. Lancement de l'application
## A.2. Lancement de l'application
Comme dans le précédent TP lancez un serveur HTTP et la compilation du projet **dans deux terminaux côte à côte** ([terminaux splittés](https://code.visualstudio.com/docs/editor/integrated-terminal#_terminal-splitting)) :
......@@ -67,7 +66,7 @@ Comme dans le précédent TP lancez un serveur HTTP et la compilation du projet
_que vous avez créé dans le précédent TP ([TP2 / A.5. Créer un script de build personnalisé](https://gitlab.univ-lille.fr/js/tp2/-/blob/master/A-preparatifs.md#a5-cr%C3%A9er-un-script-de-build-personnalis%C3%A9))_
_puis modifié pour [compiler avec webpack+babel](https://gitlab.univ-lille.fr/js/tp2/-/blob/master/C-modules.md#c3-rendre-les-modules-compatibles-avec-les-vieux-navigateurs)_
3. **Vérifiez dans le navigateur que la page index.html s'affiche correctement** en ouvrant l'url http://localhost:8000.
3. **Vérifiez dans le navigateur que la page `index.html` s'affiche correctement** en ouvrant l'url http://localhost:8000.
Le résultat attendu est le suivant :
......
......@@ -18,7 +18,8 @@ _**Dans cette partie du TP, nous allons prendre en main les méthodes de base de
### B.1.1. querySelector()
**Comme vu en cours, la principale méthode pour sélectionner un élément de la page HTML est la méthode [`querySelector()`](https://developer.mozilla.org/fr/docs/Web/API/Document/querySelector).**
`querySelector()` est une méthode de la classe `Element` qui retourne une référence vers le premier élément de la page (_une balise_) qui correspond au sélecteur CSS passé en paramètre. Par exemple :
`querySelector()` est une méthode de la classe `Element` qui retourne une référence vers le premier élément de la page (_une balise_) qui correspond au sélecteur CSS passé en paramètre. \
Par exemple :
```js
document.querySelector('.pageContainer');
```
......@@ -43,20 +44,20 @@ cette instruction vous retourne la balise qui a comme classe `"pizzaList"`
<img src="images/readme/queryselector-console.png">
### B.1.2. querySelectorAll()
**La méthode [`querySelectorAll()`](https://developer.mozilla.org/fr/docs/Web/API/Document/querySelectorAll) permet de récupérer non pas un, mais tous les éléments qui correspondent au sélecteur CSS passé en paramètre.**
**La méthode [`querySelectorAll()`](https://developer.mozilla.org/fr/docs/Web/API/Document/querySelectorAll) permet de récupérer non pas un, mais TOUS les éléments qui correspondent au sélecteur CSS passé en paramètre** (_sous la forme d'un tableau_).
Affichez dans la console :
1. **la liste des liens du menu de navigation** ("La carte", "À propos" et "Ajouter une pizza")
1. **la liste des liens (`<a href>`) du menu de navigation** ("La carte", "À propos" et "Ajouter une pizza") cf. capture ci-dessous
2. **la liste des `<li>` contenant le prix de toutes les pizzas**
<img src="images/readme/queryselectorall-console.png">
## B.2. Modifier des éléments
### B.2.1. innerHTML
**La propriété [`innerHTML`](https://developer.mozilla.org/fr/docs/Web/API/Element/innertHTML) permet à la fois de lire et de modifier le contenu d'un Element HTML** (_tout ce qui est compris **entre** les balises ouvrantes et fermantes_)
**La propriété [`innerHTML`](https://developer.mozilla.org/fr/docs/Web/API/Element/innertHTML) permet à la fois de lire ET de modifier le contenu d'un Element HTML** (_tout ce qui est compris **entre** les balises ouvrantes et fermantes_)
1. Affichez dans la console le **titre de la deuxième pizza** (_la chaîne de caractères_ `"Napolitaine"`)
2. **Ajoutez au logo** (_grâce à la propriété `innerHTML`_) le code HTML suivant :
2. **Dans le fichier `main.js`, ajoutez au logo** (_grâce à la propriété `innerHTML`_) le code HTML suivant :
```html
<small>les pizzas c'est la vie</small>
```
......@@ -71,14 +72,24 @@ Affichez dans la console :
<img src="images/readme/pizzaland-innerhtml.png">
> _**Rappel :** innerHTML est accessible en écriture ET en lecture !_
### B.2.2. getAttribute/setAttribute
**Les méthodes [`getAttribute()`](https://developer.mozilla.org/fr/docs/Web/API/Element/getAttribute) et [`setAttribute()`](https://developer.mozilla.org/fr/docs/Web/API/Element/setAttribute) de la classe `Element` permettent de lire, d'ajouter ou de modifier des attributs HTML.**
> _**Rappel :** Les **attributs** HTML, ce sont les paires `clé="valeur"` que l'on peut trouver dans les balises ouvrantes (comme `src`, `href`, etc.)._
1. Affichez dans la console **l'url du 2e lien contenu dans le footer** (`"https://www.iut-a.univ-lille.fr/"`)
2. **Ajoutez la classe CSS `"active"`** au premier lien du menu ("La carte")
2. Dans le fichier `main.js`, **ajoutez la classe CSS `"active"`** au premier lien du menu ("La carte")
<img src="images/readme/pizzaland-setattribute.png">
> _**NB :** pour associer plusieurs classes CSS à une seule balise, il suffit de les séparer par un espace à l'intérieur de l'attribut `class`. Pour cet exercice on souhaite donc obtenir le code HTML suivant :_
> ```html
> <a href="/" class="pizzaListLink active">
> ```
> _(Notez l'espace entre "pizzaListLink" et "active")_
## Étape suivante <!-- omit in toc -->
Maintenant que l'on est capable de sélectionner / modifier des éléments HTML, nous allons voir dans le prochain exercice comment détecter les événements : [C. Les événements](./C-evenements.md).
\ No newline at end of file
Maintenant que l'on est capable de sélectionner et modifier des éléments HTML, nous allons voir dans le prochain exercice comment détecter des événements : [C. Les événements](./C-evenements.md).
\ No newline at end of file
......@@ -66,9 +66,11 @@ link.addEventListener('click', handleClick); // écoute l'événement
La technique de navigation vue à l'instant (_masquer/afficher des balises_) est pratique pour des applications simples, où tout le contenu HTML est déjà généré côté serveur (_en JAVA, en PHP, en C# ou encore avec Node.JS_). \
**En revanche elle n'est pas très adaptée aux SPA où en général on a du contenu dynamique à injecter dans la page.**
On va donc revenir à la principale technique de navigation employée dans les SPA, celle que l'on utilisait jusque là : **générer dynamiquement, en JS, le code HTML de la page en fonction de ce que demande l'utilisateur** (_comme on le faisait avec la `PizzaList` par exemple_).
On va donc revenir à la principale technique de navigation employée dans les SPA, celle que l'on utilisait jusque là : **générer dynamiquement (en JS) le code HTML de la page en fonction de ce que demande l'utilisateur** (_comme on le faisait avec la `PizzaList` par exemple_).
Pour approfondir cette technique de navigation et **permettre de passer d'une page à une autre**, je vous propose de nous appuyer sur la classe `Router` que vous avez développée lors du précédent TP ([TP2 / D.3. Propriétés et méthodes statiques : La classe Router](https://gitlab.univ-lille.fr/js/tp2/-/blob/master/D-poo-avancee.md#d3-propri%C3%A9t%C3%A9s-et-m%C3%A9thodes-statiques-la-classe-router)) et dont ma version se trouve dans ce repo (`src/Router.js`).
Pour approfondir cette technique de navigation et **permettre de passer d'une page à une autre**, je vous propose de nous appuyer sur la classe `Router` que vous avez développée lors du TP2 (_[D.3. Propriétés et méthodes statiques : La classe Router](https://gitlab.univ-lille.fr/js/tp2/-/blob/master/D-poo-avancee.md#d3-propri%C3%A9t%C3%A9s-et-m%C3%A9thodes-statiques-la-classe-router)_) et dont ma version se trouve dans ce repo (_vous pouvez la consulter dans [`src/Router.js`](./src/Router.js)_).
Cette classe permet d'afficher un titre et un Component dans la page à l'aide de sa propriété statique `Router.routes` et de sa méthode statique `Router.navigate()`.
**L'objectif de l'exercice ici est simple : faire en sorte que lorsque l'utilisateur clique sur un des liens du menu, on affiche un contenu différent dans la page grâce à la méthode `Router.navigate()`.**
......@@ -77,15 +79,15 @@ Pour approfondir cette technique de navigation et **permettre de passer d'une pa
1. **Dans `src/main.js`, commencez par créez des `Component` pour les différents liens du menu :**
```js
const pizzaList = new PizzaList([]),
const pizzaList = new PizzaList(data),
aboutPage = new Component('section', null, 'Ce site est génial'),
pizzaForm = new Component('section', null, 'Ici vous pourrez ajouter une pizza');
```
> _**NB1 :** `pizzaList` existe déjà, on ajoute ici juste `aboutPage` et `pizzaForm`._
> _**NB1 :** `pizzaList` était déjà déclarée, effacez son ancienne déclaration et remplacez la par celle-ci. On ajoute par ailleurs `aboutPage` et `pizzaForm`._
> _**NB2 :** pour le moment on utilise pour ces 2 nouvelles pages des `Component` très simples, "en dur", mais on les passera dans des classes spécifiques plus tard._
**Puis ajoutez les routes correspondantes dans notre Router :**
**Puis, toujours dans le `main.js`, ajoutez les routes correspondantes dans le Router :**
```js
Router.routes = [
{ path: '/', page: pizzaList, title: 'La carte' },
......@@ -103,25 +105,30 @@ Pour approfondir cette technique de navigation et **permettre de passer d'une pa
```js
Router.menuElement = document.querySelector('.mainMenu');
```
> _**NB :** en faisant cela on envoie au Router une **référence vers la balise `<ul class="mainMenu">`** qui contient le menu de navigation (cela nous évitera de faire référence à `document` dans la classe `Router` et en plus ça reste cohérent avec le fonctionnement des propriétés `titleElement` et `contentElement`)_
> _**NB :** en faisant cela on stocke dans le Router une **référence vers la balise `<ul class="mainMenu">`** qui contient tout le menu de navigation (cela nous évitera d'avoir à faire référence à `document` dans la classe `Router` et en plus ça reste cohérent avec le fonctionnement des autres propriétés `Router.titleElement` et `Router.contentElement`)_
`Router.menuElement` est en fait un "setter" dont je vous fourni le code de base à compléter (_à coller **dans** le corps de la classe `Router`_) :
`Router.menuElement` sera en fait **un "setter"** (_comme vu dans le [TP2 / D. POO avancée](https://gitlab.univ-lille.fr/js/tp2/-/blob/master/D-poo-avancee.md#d42-rappels-getterssetters) un setter est une méthode "déguisée" en propriété !_) dont je vous fournis le code à compléter (_à coller **dans** le corps de la classe `Router`_) :
```js
static #menuElement;
static set menuElement(element) {
static #menuElement; // propriété statique privée
/**
* Indique au Router la balise HTML contenant le menu de navigation
* Écoute le clic sur chaque lien et déclenche la méthode navigate
* @param element Élément HTML qui contient le menu principal
*/
static set menuElement(element) { // setter
this.#menuElement = element;
// au clic sur n'importe quel lien contenu dans "element"
// au clic sur n'importe quel lien (<a href>) contenu dans "element"
// déclenchez un appel à Router.navigate(path)
// où "path" est la valeur de l'attribut `href=".."` du lien cliqué
}
```
À l'aide de ce setter, **détectez le clic sur n'importe quel lien du menu** (_actuellement il n'y a en a que 3, mais votre code doit fonctionner quelque soit le nombre de liens_) et **affichez dans la console l'attribut `href` du lien qui a été cliqué**. \
Par exemple si l'utilisateur clique sur le lien **"À propos"** la console doit afficher la chaîne de caractères **`"/a-propos"`**
À l'aide de ce setter, **détectez le clic sur n'importe quel lien du menu** (_actuellement il n'y a en a que 3, mais votre code doit fonctionner quelque soit le nombre de liens, il faudra donc une boucle_) et lorsqu'un clic est détecté **affichez dans la console l'attribut `href` du lien qui a été cliqué**. \
Par exemple si l'utilisateur clique sur le lien **"À propos"**, la console doit afficher la chaîne de caractères **`"/a-propos"`** (_l'URL du lien_)
> _**NB1 :** vous aurez besoin pour celà de la propriété [`event.currentTarget` _(mdn)_](https://developer.mozilla.org/fr/docs/Web/API/Event/currentTarget) et de la méthode [`element.getAttribute()` _(mdn)_](https://developer.mozilla.org/fr/docs/Web/API/Element/getAttribute)_
> _**NB1 :** vous aurez besoin pour cela de la propriété [`event.currentTarget` _(mdn)_](https://developer.mozilla.org/fr/docs/Web/API/Event/currentTarget) et de la méthode [`element.getAttribute()` _(mdn)_](https://developer.mozilla.org/fr/docs/Web/API/Element/getAttribute)_
> _**NB2 :** en cas de **problème de scope**, relisez donc la fin du paragraphe [C.1. Rappels](#c1-rappels), juste au cas où..._
> _**NB2 :** en cas de **problème de scope**, rappelez vous que dans un callback d'événement, la valeur de `this` est parfois modifiée ! Relisez donc la fin du paragraphe [C.1. Rappels](#c1-rappels), juste au cas où..._
3. **Pour terminer, maintenant que vous avez récupéré le `href` du lien cliqué, il ne vous reste plus qu'à invoquer la méthode `Router.navigate()` en lui passant en paramètre le `href` en question !**
......
......@@ -9,10 +9,9 @@ _**Dans cette partie du TP, nous allons travailler sur les formulaires et créer
- [D.2. Préparatifs : La classe `Page`](#d2-préparatifs-la-classe-page)
- [D.3. Le formulaire d'ajout de pizza](#d3-le-formulaire-dajout-de-pizza)
- [D.4. La validation de la saisie](#d4-la-validation-de-la-saisie)
- [Étape suivante](#étape-suivante)
## D.1. Un peu de théorie
_**On utilise généralement l'API DOM avec les formulaires pour 2 choses :**_
_**Comme vu en cours, on utilise généralement l'API DOM avec les formulaires pour 2 choses :**_
1. **Récupérer les valeurs saisies par l'utilisateur** (_et afficher des messages d'erreur par exemple_)
2. **Détecter la soumission du formulaire** (_pour envoyer des données en AJAX à un webservice par exemple_)
......@@ -25,11 +24,11 @@ En imaginant le formulaire suivant :
```
On peut lire la valeur tapée par l'utilisateur dans le champ `"message"` avec la propriété [`.value`](https://developer.mozilla.org/fr/docs/Web/HTML/Element/Input#value) de l'élément `<input type="text">`, et l'événement [`submit`](https://developer.mozilla.org/fr/docs/Web/API/HTMLFormElement/submit_event_) de la balise `<form>` :
```js
const form = document.querySelector('form'),
input = form.querySelector('input[name=message]');
const form = document.querySelector('form'), // balise form
input = form.querySelector('input[name=message]'); // balise <input name="message">
form.addEventListener('submit', function(event) {
event.preventDefault();
form.addEventListener('submit', event => { // détection de la soumission
event.preventDefault(); // on empêche la page de se recharger
console.log('Le formulaire a été soumis avec la valeur :'+input.value);
});
```
......@@ -40,8 +39,8 @@ form.addEventListener('submit', function(event) {
**Vous allez coder votre formulaire d'ajout de pizza dans une classe à part, `PizzaForm` (comme on l'a fait pour la `PizzaList`). Et dans cette nouvelle classe il faudra détecter la soumission du formulaire grâce à l'évènement `submit`** (_comme dans l'exemple ci-dessus_).
Hors pour le moment, les "pages" de notre application (_comme la `PizzaList`, ou notre future `PizzaForm`_) **ne sont pas capables d'ajouter des écouteurs d'événements** sur le code HTML qu'elles génèrent. \
**Pourquoi ?** Et bien parce que leur méthode `render()` ne fait que retourner une chaîne de caractères et c'est le `Router` qui se charge de l'ajouter dans le DOM. La page n'a donc aucune connaissance ni du DOM, ni du moment le code HTML qu'elle a généré est ajouté à l'écran. 😢
Or pour le moment, les "pages" de notre application (_comme la `PizzaList`, ou notre future `PizzaForm`_) **ne sont pas capables d'ajouter des écouteurs d'événements** sur le code HTML qu'elles génèrent. \
**Pourquoi ?** Et bien parce que leur méthode `render()` ne fait que retourner une chaîne de caractères et c'est le `Router` qui se charge de l'ajouter dans le DOM. La page n'a donc aucune connaissance ni du DOM, ni du moment à partir duquel le code HTML qu'elle a généré est ajouté à l'écran. 😢
Ce que je vous propose c'est d'ajouter une nouvelle méthode (`mount(element)`) qui va permettre au `Router` d'indiquer à chaque page quelle est la balise HTML (_l'élément du DOM_) dans laquelle elle vient de s'afficher : **de cette manière les pages auront d'un seul coup deux infos : le fait qu'elles viennent d'être affichée à l'écran, et aussi dans quelle balise HTML !**
......@@ -66,12 +65,14 @@ C'est grâce à ces deux infos que nos pages pourront enfin **ajouter des écout
> _**NB2 :** Comme vous le voyez la classe `Page` ajoute à la classe `Component` :_
> - _une **propriété `element`**_
> - _une **méthode `mount()`** qui se contente de stocker la valeur de `element`_\
> _C'est cette méthode qui pourra être surchargée par les pages pour ajouter des écouteurs d'événements_
> _C'est cette méthode qui pourra être surchargée par les différentes pages de notre application pour y ajouter des écouteurs d'événements par exemple._
2. **Faites hériter la `PizzaList` de la classe `Page`, et adaptez le constructeur pour respecter le nouveau constructeur parent** (_celui de `Page` désormais_) :
```js
import Page from './Page';
import PizzaThumbnail from '../components/PizzaThumbnail';
export default class PizzaList extends Page {
#pizzas;
......@@ -124,15 +125,22 @@ C'est grâce à ces deux infos que nos pages pourront enfin **ajouter des écout
submit(event) {}
}
```
> _**NB1 :** Vous remarquez qu'ici **la méthode `render()` retourne directement le code HTML sous forme de template string** sans utiliser d'autres `Component`._ \
> _C'est en effet beaucoup plus simple que d'imbriquer des Component dans des Component dans des Component, comme on a pu le faire dans le précédent TP avec la classe `PizzaThumbnail` par exemple : le but était à l'époque juste de vous faire travailler les notions de composition et d'héritage, maintenant on privilégie la lisibilité du code._
> _**NB2 :** avant la template string, j'ai mis un commentaire `/*html*/`. Le but est de permettre à l'extension vscode [es6-string-html](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html) de faire de la **coloration syntaxique du code HTML contenu à l'intérieur de votre chaîne JS** !!_ \
> _Si ça vous intéresse n'hésitez pas à l'installer (_<kbd>CTRL</kbd>+<kbd>SHIFT</kbd>+<kbd>X</kbd>_)_
2. **Utilisez cette classe pour créer la constante `pizzaForm` dans le `main.js`.** À la place de :
```js
const pizzaList = new PizzaList([]),
const pizzaList = new PizzaList(data),
aboutPage = new Component('p', null, 'ce site est génial'),
pizzaForm = new Component('p', null, 'ici vous pourrez ajouter une pizza');
```
vous aurez maintenant :
```js
const pizzaList = new PizzaList([]),
const pizzaList = new PizzaList(data),
aboutPage = new Component('p', null, 'ce site est génial'),
pizzaForm = new PizzaForm();
```
......@@ -141,9 +149,9 @@ C'est grâce à ces deux infos que nos pages pourront enfin **ajouter des écout
<img src="images/readme/pizzaform.png" >
3. **Dans la méthode `mount()` de la classe `PizzaForm` détectez la soumission du formulaire à l'aide des méthodes `querySelector` et `addEventListener`**. Cet écouteur d'événement devra déclencher l'appel à la méthode `submit()` de l'instance.
3. **Dans la méthode `mount()` de la classe `PizzaForm`, détectez la soumission du formulaire à l'aide des méthodes `this.element.querySelector()` et `addEventListener`**. Cet écouteur d'événement devra déclencher l'appel à la méthode `submit()` de `PizzaForm`.
> _**NB :** Souvenez vous de la méthode `event.preventDefault()` et vérifiez que la soumission du formulaire n'entraîne pas un rechargement de page par exemple avec l'onglet Network/Réseau des devtools_
> _**NB :** Souvenez vous de la méthode `event.preventDefault()` et vérifiez que la soumission du formulaire n'entraîne pas un rechargement de page en utilisant l'onglet "Network"/"Réseau" des devtools_
4. Au submit, **affichez dans la console la valeur saisie par l'utilisateur dans l'input "name"**.
......@@ -154,5 +162,7 @@ C'est grâce à ces deux infos que nos pages pourront enfin **ajouter des écout
3. **Si le champ "name" n'est pas vide, afficher une alerte "La pizza xxxxx a été ajoutée"** (où "xxxxx" correspond au nom qu'a saisi l'utilisateur) **et videz le champ de saisie** pour permettre à l'utilisateur de saisir une nouvelle pizza.
## Étape suivante
> _**NB :** pour modifier la valeur d'un champ, sachez que la propriété [`.value`](https://developer.mozilla.org/fr/docs/Web/HTML/Element/Input#value) de l'élément input est accessible aussi en écriture !_
## Étape suivante <!-- omit in toc -->
Pour terminer ce TP, voyons comment améliorer la navigation dans notre application à l'aide de la History API : [E. Navigation avancée](./E-navigation-avancee.md).
\ No newline at end of file
......@@ -8,11 +8,11 @@ _**Pour terminer ce TP, nous allons finaliser le mécanisme de navigation dans l
- lorsqu'on recharge la page dans le navigateur (F5) on doit afficher la page sur laquelle l'utilisateur se trouvait
## Sommaire <!-- omit in toc -->
- [E.1. activation du menu](#e1-activation-du-menu)
- [E.1. Activation du menu](#e1-activation-du-menu)
- [E.2. History API](#e2-history-api)
- [E.3. Le Deeplinking](#e3-le-deeplinking)
- [E.3. Le deep linking](#e3-le-deep-linking)
## E.1. activation du menu
## E.1. Activation du menu
**Actuellement lorsqu'on clique sur un lien du menu, rien n'indique dans le menu sur quelle page on se trouve.** On va donc remédier à ça en ajoutant une **classe CSS** sur le lien qui correspond à la page sur laquelle on se rend (_notez le trait plus grand sur le lien cliqué_) :
<img src="./images/readme/nav-active.gif">
......@@ -49,14 +49,14 @@ Ce qui permet ensuite d'utiliser les boutons précédent/suivant du navigateur (
- le **callback [`window.onpopstate` _(mdn)_](https://developer.mozilla.org/fr/docs/Web/API/WindowEventHandlers/onpopstate)** qui permet d'appeler une fonction lors de l'utilisation des boutons précédent/suivant du navigateur
- et la **propriété [`document.location` _(mdn)_](https://developer.mozilla.org/fr/docs/Web/API/Document/location)** qui permet d'obtenir des informations sur l'URL de la page courante
Dans `src/main.js`, assignez une fonction (une arrow function par exemple) à `window.onpopstate` et placez-y pour le moment juste un `console.log(document.location)`.
**Dans `src/main.js`, assignez une fonction (_une arrow function par exemple_) à `window.onpopstate`** et placez-y pour le moment juste un `console.log(document.location)`.
Rechargez la page, naviguez un peu via le menu et les boutons précédent/suivant et inspectez dans la console le contenu de `document.location`, vous devriez y trouver quelque chose qui peut vous aider à afficher la bonne page...
Rechargez la page, naviguez un peu via le menu et les boutons précédent/suivant et inspectez dans la console ce que contient `document.location`, **vous devriez y trouver quelque chose qui peut vous aider à afficher la bonne page**...
> _**NB :** faites attention à ne pas invoquer `window.history.pushState()` lors du `onpopstate` sinon cela va quelque peu "casser" la navigation avec les boutons précédent/suivant en créant une "inception"..._
> _**NB :** faites attention à ne pas invoquer `window.history.pushState()` lors du `onpopstate` sinon cela va "casser" la navigation avec les boutons précédent/suivant en créant une "inception"..._
## E.3. Le Deeplinking
## E.3. Le deep linking
_**Notre application est presque terminée, à un détail près : l'absence de [deep linking](https://fr.wikipedia.org/wiki/Lien_profond).**_
......@@ -66,17 +66,17 @@ En effet, si vous vous rendez directement sur http://localhost:8000/a-propos dan
En fait, lorsque vous lancez la requête en entrant cette URL dans la barre d'adresse du navigateur, le serveur http lancé avec `npx serve` cherche par défaut à trouver un fichier `a-propos.html` ou bien un fichier `index.html` dans un sous dossier `/a-propos/`. Autant dire que ça n'a aucune chance de fonctionner comme ça.
Heureusement `npx serve` dispose d'une option `-s` qui permet de rediriger toutes les 404 vers le `index.html` de la racine : ainsi notre JS se chargera et il ne restera plus qu'à déterminer (en JS) quelle page afficher grâce à l'URL courante.
Heureusement `npx serve` dispose d'une option `-s` qui permet de rediriger toutes les 404 vers le `index.html` de la racine : ainsi notre page HTML se chargera correctement et il ne restera plus qu'à déterminer (en JS) quelle page afficher grâce à l'URL courante. Facile !
1. **Stoppez le serveur HTTP `npx serve -l 8000` et relancez le avec cette fois l'option `-s` :**
1. **Stoppez donc le serveur HTTP `npx serve -l 8000` et relancez le avec cette fois l'option `-s` :**
```bash
npx serve -s -l 8000
```
Rechargez la page http://localhost:8000/a-propos : la 404 a disparu est le site s'affiche ! Malheureusement c'est encore la `PizzaList` qui est affichée et pas la page "À propos"...
Rechargez la page http://localhost:8000/a-propos : la 404 a disparu est le site s'affiche ! Malheureusement c'est la `PizzaList` qui s'affiche et pas la page "À propos"...
2. **Maintenant que notre site s'affiche quelque soit l'URL de la page, reste à faire en sorte que l'on affiche la page qui correspond à l'URL demandée par l'utilisateur.**
2. **Maintenant que notre site s'affiche quelque soit l'URL de la page, il ne reste donc plus qu'à faire en sorte que l'on affiche la bonne page : c'est à dire celle qui correspond à l'URL demandée par l'utilisateur.**
Actuellement, au chargement, notre application affiche toujours la `PizzaList` en premier car dans notre `main.js` nous avons le code :
Actuellement, au chargement, notre application affiche systématiquement la `PizzaList` en premier car dans notre `main.js` nous avons le code :
```js
Router.navigate('/');
```
......
......@@ -4,12 +4,13 @@
- Savoir manipuler la page HTML avec l'API DOM
- Savoir détecter les actions de l'utilisateur avec les Event
- Être capable de gérer des formulaires avec JS
- Utiliser la History API
## Sommaire
Pour plus de clarté, les instructions du TP se trouvent dans des fichiers distincts (un fichier par sujet), procédez dans l'ordre sinon, ça fonctionnera beaucoup moins bien ! :
Pour plus de clarté, les instructions du TP se trouvent dans des fichiers distincts (un fichier par sujet), procédez dans l'ordre sinon, ça fonctionnera beaucoup moins bien !
1. [A. Préparatifs](A-preparatifs.md)
2. [B. Les bases de l'API DOM](B-les-bases.md)
3. [C. Les événements](C-evenements.md)
4. [D. Les formulaires](D-formulaires.md)
5. [E. Formulaires et navigation](E-navigation.md)
\ No newline at end of file
5. [E. Navigation avancée](./E-navigation-avancee.md)
\ No newline at end of file
images/readme/boutons-prev-next.gif

1.41 MiB | W: | H:

images/readme/boutons-prev-next.gif

1.71 MiB | W: | H:

images/readme/boutons-prev-next.gif
images/readme/boutons-prev-next.gif
images/readme/boutons-prev-next.gif
images/readme/boutons-prev-next.gif
  • 2-up
  • Swipe
  • Onion skin
images/readme/changement-url.gif

933 KiB | W: | H:

images/readme/changement-url.gif

1.82 MiB | W: | H:

images/readme/changement-url.gif
images/readme/changement-url.gif
images/readme/changement-url.gif
images/readme/changement-url.gif
  • 2-up
  • Swipe
  • Onion skin
images/readme/deeplinking.gif

2.87 MiB | W: | H:

images/readme/deeplinking.gif

4.56 MiB | W: | H:

images/readme/deeplinking.gif
images/readme/deeplinking.gif
images/readme/deeplinking.gif
images/readme/deeplinking.gif
  • 2-up
  • Swipe
  • Onion skin
images/readme/nav-active.gif

1010 KiB | W: | H:

images/readme/nav-active.gif

743 KiB | W: | H:

images/readme/nav-active.gif
images/readme/nav-active.gif
images/readme/nav-active.gif
images/readme/nav-active.gif
  • 2-up
  • Swipe
  • Onion skin
images/readme/nav-simple.gif

1.83 MiB | W: | H:

images/readme/nav-simple.gif

2.15 MiB | W: | H:

images/readme/nav-simple.gif
images/readme/nav-simple.gif
images/readme/nav-simple.gif
images/readme/nav-simple.gif
  • 2-up
  • Swipe
  • Onion skin
images/readme/newscontainer.png

1.2 MiB | W: | H:

images/readme/newscontainer.png

623 KiB | W: | H:

images/readme/newscontainer.png
images/readme/newscontainer.png
images/readme/newscontainer.png
images/readme/newscontainer.png
  • 2-up
  • Swipe
  • Onion skin
images/readme/pizzaform.png

1.19 MiB | W: | H:

images/readme/pizzaform.png

653 KiB | W: | H:

images/readme/pizzaform.png
images/readme/pizzaform.png
images/readme/pizzaform.png
images/readme/pizzaform.png
  • 2-up
  • Swipe
  • Onion skin
images/readme/pizzaland-00.png

1.05 MiB | W: | H:

images/readme/pizzaland-00.png

1020 KiB | W: | H:

images/readme/pizzaland-00.png
images/readme/pizzaland-00.png
images/readme/pizzaland-00.png
images/readme/pizzaland-00.png
  • 2-up
  • Swipe
  • Onion skin
images/readme/pizzaland-05.png

371 KiB

images/readme/pizzaland-innerhtml.png

335 KiB | W: | H:

images/readme/pizzaland-innerhtml.png

36.8 KiB | W: | H:

images/readme/pizzaland-innerhtml.png
images/readme/pizzaland-innerhtml.png
images/readme/pizzaland-innerhtml.png
images/readme/pizzaland-innerhtml.png
  • 2-up
  • Swipe
  • Onion skin
images/readme/pizzaland-nav.gif

52.9 KiB

images/readme/pizzaland-setattribute.png

335 KiB | W: | H:

images/readme/pizzaland-setattribute.png

26.8 KiB | W: | H:

images/readme/pizzaland-setattribute.png
images/readme/pizzaland-setattribute.png
images/readme/pizzaland-setattribute.png
images/readme/pizzaland-setattribute.png
  • 2-up
  • Swipe
  • Onion skin
images/readme/queryselector-pizzaList.png

553 KiB | W: | H:

images/readme/queryselector-pizzaList.png

252 KiB | W: | H:

images/readme/queryselector-pizzaList.png
images/readme/queryselector-pizzaList.png
images/readme/queryselector-pizzaList.png
images/readme/queryselector-pizzaList.png
  • 2-up
  • Swipe
  • Onion skin
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment