Cours JavaScript/ intro aux frameworks JS ESTIA 2019-2020

De $1

Séance 1 : prise de contact, premier exercices en JavaScript

Nous avons parcouru ensemble le module 1 du MOOC, et une partie du module 2, et fait plusieurs exercices en live coding:

  1. Exercice fait à l'aide de fichiers séparés index.html, js/script.js, css/styles.css, et des images dans un répertoire assets. Zip de l'exercice ici : ESTIA.zip 
     
  2. Exercices sur les tableaux et les boucles for et itérateurs forEach, avec à fin un exemple de requête fetch pour aller cherches des données distantes sur Metallica et afficher les membres du groupe dans la console. Ouvrir les onglets "JavaScript" et "Console" de jsbin, puis cliquer sur bouton "run" et regarder la console : https://jsbin.com/veseroc/edit?html,js,console

  3. Exercice sur les équations du second degrès, utilisation de champs <input type="number>, d'événements de type input pour récupérer les valeurs de a, b et c dans la formule y = ax^2 + bx + c. Calcul en temps réel (au fur et à mesure qu'on change les valeurs) du déterminant, des racines et dessins graphique de la courbe à l'aide d'une librairie externee  : https://jsbin.com/hoherut/edit?js,output

  4. Exercice fait à la fin de la journée : dessin et animation en JavaScript à l'aide de l'API de l'élément canvas de HTML5. On a dessiné un petit monstre qui se déplace à 60 images/seconde, déplacement avec les flèches du clavier : https://jsbin.com/werasog/edit?html,output

Séance 2 matin : introduction aux classes et objets JavaScript que l'on peut instancier avec des "new"

Exemples en live coding:

Séance 2 après-midi : premiers pas avec React

Supports de cours :

Exercices d'introduction, dans une IDE en ligne

On peut faire du react dans JsBin/JsFiddle/CodePen, mais croyez-moi, juste pour de petits exemples !

Exercice à faire en vous aidant des exercices précédents:

Pour vous donner une idée du résultat attendu,voici l'équivalent en VueJS: http://jsbin.com/guwetoy/1/edit?html,output

Je conseille de partir de cet exemple React: le composant en classe ES6 

En vous aidant de l'exemple fait en classe en live coding, voud devrez faire incrémentalement, en testant après chaque étape :

  1. Créez un <div> et affichez dedans un composant Root avec React (l'App des exemples)
     
  2. Affichez un tableau de hobbies dans ce <div> (foot, tennis, jeux video, etc.) sous la forme d'une liste. Chaque hobby sera un <li>. Vous fournirez des hobbies par défaut.
     
  3. Ajoutez un bouton 'Nouveau Hobby' et un champ input pour saisir le nom du hobbie à rajouter. La liste doit se mettre à jour.
     
  4. Rendez les hobbies clickables pour qu'on puisse les supprimer
     
  5. Un message <p>Hobby supprimé !</p> devra apparaitre lorsqu'un hobby est supprimé
     
  6. Ajoutez un compteur de hobbies (<p>Hobbies: 4</p>) au-dessus de la liste des hobbies, qui indiquera le nombre de hobbies dans la liste.
     
  7. Vous changerez les styles CSS des éléments de la liste pour qu'ils s'affichent en rouge et vert à chaque ligne, en alternance. Vous utiliserez aussi des classes CSS dynamiques pour afficher le compteur en rouge si le nombre de hobbies est supérieur à trois, en vert sinon. 
     
  8. Chaque <li>, chaque hobby, sera maintenant dans un composant <Hobby/> 

ICI CORRRECTION FAITE EN CLASSEhttps://codepen.io/w3devcampus/pen/xxGOPXO?editors=0010

ICI UNE CORRECTION AVANCEE (qui utilise la "destructuration" et les arrow functions en masse)https://codepen.io/w3devcampus/pen/xxKeJZW

Séance 3 : on continue avec React (intro au mode CLI)

Exercices avec un environnement "CLI"

Si on va voir la page de facebook sur "how to start with React", il y a un chapitre qui concerne le mode "CLI": https://reactjs.org/docs/add-react-to-a-new-app.html

  1. Vous devez avoir nodeJS correctement installé (node, npm, etc, tout ceci doit fonctionner...)
     
  2. Installez l'extension Google Chrome "React Developer Tools" (https://chrome.google.com/webstore/d...jfkapdkoienihi), elle existe aussi pour Firefox.
     
  3. Installez une bonne fenêtre terminal pour Windows -si vous êtes sous windows comme http://cmder.net/ ou autre (github bash, etc.) si je vous vois avec une fenêtre DOS basique vous allez m'entendre ! Vous pouvez à la rigueur utiliser le terminal de Visual Studio Code.
     
  4. Ouvrir la ligne de commande et exécuter la commande "npm install -g create-react-app",
    • Pour vérifier que ça fonctionne, créez un autre répertoire nommé "react_cli" et cd dedans,
    • Executez "create-react-app hello-world" (ça prend du temps, quelques minutes)...
    • Allez dans le répertoire créé (cd hello-world), et faites "npm install" (là aussi, quelques minutes)
    • Exécutez le programme en tapant "npm start", ça doit ouvrir automatiquement le browser sur le port 3000 et afficher une page avec le logo React qui tourne.
    • Editez le code du fichier src/App.js, changez le texte et sauvez -> la page Web de l'application doit se rafraichir automatiquement.
       
  5. Maintenant on va étudier le code, regardez les fichiers html, js, les configs etc.
     
  6. Essayez de modifier la partie "render" de App.js... hmmm ok. Bon, on va faire un simple composant <Username name="toto"/> qu'on va mettre dans un sous répertoire "components" dans les sources, il va simplement afficher un nom passé en attribut/props dans un paragraphe en couleur. Vous ajouterez dans <App/> Plusieurs instances de ce composant.

Exercice 1: refaire dans le projet les hobbies en mode CLI !

Exercice 2: on va modifier cet exemple pour utiliser un composant <Hobby> qui va afficher le Hobby. En d'autres termes, le rendu d'un hobby (un <li>...</li>) ne se fera pas dans <ListeHobbies> mais dans <Hobby>

Exercice 3: On va modifier cet exemple pour utiliser des données récupérées sur un WebService de l'OpenData. Par exemple on va afficher des infos sur le groupe de rock Metallica (données ici https://wasabi.i3s.unice.fr/search/artist/Metallica)

  • Voir avec le prof comment récupérer des données avec fetch.
  • Creer un composant <GroupeRock> qui va récupérer sur l'URL de la description de Metallica des infos sur le groupe et les afficher (Nom, photo, description du goupe...)
  • Creer un composant <MembresDuGroupe> qui affichera les membres du goupe.

Exercice 4 : utiliser un joli tableau en provenance de la bibliothèque de composants MaterialUI, très populaire au sein des développeurs React

  1. Regarder le getting started du site Web de MaterialUI pour voir comment inclure cette librairie de composants graphiques dans votre projet.
  2. Regarder la doc de l'élément table, elle contient de nombreux exemples avec le code source.
  3. Regardez aussi s'il y a un chapitre concernant les tables dans le livre "MaterialUI Cookbook" qui vous a été distribué.
     
  4. Ajoutez maintenant une table MaterialUI dans un composant à vous intitulé MyTable.js pour tester
  5. Modifiez le template de <GroupeDeRock> et <MembresDuGroupe> pour afficher les membres du groupe de manière plus jolie...
    • On trouve de nombreuses vidéos d'exemple d'utilisation de l'élément table de Material UI.
  • Ici correction avec hobbies, material-ui table, router etc...  : hello-world.zip , faire unzip, cd dans le dossier, npm install puis npm start 

Séance 4 : premiers pas avec Angular

Supports de cours : 

1 : création d'une application "squelette"

  1. Installer angular-cli : dans une fenêtre de terminal, tapez la commande "npm install -g @angular/cli" (éventuellement avec "sudo" avant si vous êtes sous Linux ou Mac OS)

  2. Créez un répertoire "exo1Angular" et faites cd dans ce répertoire,
  3. Générez une application "squelette" angular en tapant la commande "ng new angular-framework-intro"
  4. Faites cd angular-framework-intro et ouvrez visual studio code sur ce répertoire (commande "code ." sur Mac)
  5. Faites npm install pour installer les modules nécessaires (pour l'application et pour l'environnement de développement)
  6. Exécutez le projet en lançant la commande ng serve --open dans le répertoire
  7. Ok, maintenant faites "view source" sur la page, que remarquez-vous ? Comparez avec React et VueJS... Qu'en déduisez-vous ? A propos, est-ce qu'on a installé une extension dans le browser ?
  8. Etudions maintenant la structure du projet....

2 : affichage d'une liste d'éléments

  1. Regardez le fichier index.html, remarquez l'élément <app-root></app-root>, est-ce du HTML standard ?
  2. Regardez les fichiers src/app.component.tssrc/app.component.html et src/app.component.css
  3. Modifiez le fichier de templates app.components.html et faites ctrl-s,
  4. Regardez le fichier app.module.ts, Angular va vous obliger à mettre à jour ce fichier très régulièrement.
  5. Maintenant on va effacer le contenu du fichier de template, et on va essayer d'afficher une liste d'éléments : CA SE PASSE EN LIVE CODING (une correction sera postée ici à la fin), utilisation de *ngFor (<li *ngFor="let el of elements">...</li> si elements est la propriété du composant -un tableau de chaines de caractères-), un peu l'équivalent du v-for de VueJS.
  6. Ajout d'un bouton pour ajouter un nouvel élément, utilisation de (click)="expression" comme attribut,
  7. Regardons comment afficher une ligne verte, une ligne rouge, etc. Utilisation de [ngStyle]="{propriété CSS : expression}", écrire une fonction getColor(element) qui renverra la couleur en fonction de la valeur numérique du paramètre element (si pair rouge, si impair vert).

: création d'un nouveau composant

  • On va créer  un nouveau composant intitulé "username", qui sera juste un<li> qui affichera la valeur de la propriété username. Pour cela, on va utiliser la ligne de commande pour ajouter un nouveau composant: 

    > ng generate component username

import { Component, Input } from "@angular/core";

@Component ({
    selector: 'app-username',
    template:`
    <p>{{username}}</p>
    `
})

export class UsernameComponent {
    @Input() username :string;
}

Remarquez qu'on n'a pas utilisé ici de template html séparé, à la place on a mis le template directement sous forme de chaine de caractère entre les caractères `....`

Le @Input sert à définir une propriété qu'on pourra passer via des attributs HTML, c'est l'équivalent des "props" de VueJS et de React.

Maintenant, ajoutez des instances de ce composant dans le template app.components.html:

<app-username [username]="'Michel'"></app-username>

<app-username [username]="'John'"></app-username>

Regardez ce que cela donne.... 

Regardez aussi le fichier app.module.ts, le composant a été ajouté dans la liste des composants par la commande ng add component username.

Maintenant on veut pouvoir cliquer sur un nom et afficher un message dans le template du composant principal. On va faire comme en VueJS : envoyer un événement quand on clique sur le nom.

4 : définition d'un événement qui sera envoyé du composant "fils" vers le composant "père"

  1. Dans le composant (app/username/username.component.ts), définir un événement comme ceci: 
export class UsernameComponent {
    @Input() username :string;
    @Output() userClicked = new EventEmitter<string>(); // définition d'un événement

    onUsernameClicked() {
        this.userClicked.emit(this.username);            // émission de l'événément
    }
}

Et dans le template (app/username/username.component.ts) :

    template:`
       <p (click)="onUsernameClicked()">{{username}}</p>
    `

Ainsi, dans le template du composant (app.component.html) qui instancie ce composant, on pourra écouter l'événement "userClicked" :

<app-username [username]="'Michel1'" (userClicked)="onUserWasClicked($event)"></app-username>
<app-username [username]="'John'"    (userClicked)="onUserWasClicked($event)"></app-username>

Et maintenant on peut écrire la méthode onUserWasClicked(username) dans app.component.ts :

onUserWasClicked(username: string) {
    alert(username);
}

Testez l'application : en cliquant sur un nom, ça doit afficher une alerte avec la valeur associée.

5 : binding bi-directionnel avec [(ngModel)]="nom"

  • Définissez un champs de saisie dans le template pour une propriété "nom" que vous ajouterez dans le fichier .ts de app.component.ts
  • N'oubliez pas d'ajouter le FormsModule dans le fichier app.modules.ts sinon 1) ça ne va pas fonctionner et 2) vous allez avoir des erreurs super bizarres !
  • Dans le template, affichez la valeur de cette propriété en-dessous du champs de saisie. 
  • Tapez quelque chose dans le champ de saisie
  • Plus simple qu'en React non ? Ca ressemble au v-model de VueJS non ?

ICI UNE CORRECTION DES ETAPES PRECEDENTES (exemple fait en live). Dezippez, cd dans le repertoire, npm install puis ng serve --open

6 : Refaire l'exemple React des hobbies complet, mais en angular

 En vous aidant de l'exemple précédent :  

  1. Ajouter un compteur de hobbies (<p>Nombre de Hobbies: ...</p>) au-dessus de la liste des hobbies
     
  2. Changez le style CSS du compteur, selon sa valeur: vert si moins de 3 hobbies, rouge sinon
     
  3. Transformez les éléments <li> en un composant réutilisable <app-hobby>
     

Séance 5 : on continue en allant chercher des hobbies sur un serveur distant, utilisation d'un router

1 - Récupérer des données distantes : création d'un service

  1. On veut remplir les hobbies au démarrage de l'application en récupérant les hobbies au format JSON sur l'URL : https://my-json-server.typicode.com/...ffa/hobbies/db (au passage, j'ai utilisé les services de jsonplaceholder.typicode.com pour servir un fichier json qui se trouve sur un de mes repository github). LIVE CODING AVEC LE PROF pour voir comment créer un service
    • Commande pour créer un service : "ng generate service hobby" (va créer le fichier hobby.service.ts et le fichier pour les tests)
    • Pour aller récupérer le JSON des hobbies sur le WebService on va utiliser une méthode "simple" (angular propose aussi des méthodes plus complexes permettant de typer les données lorsqu'elles arrivent):
      • Importez le module HttpClient en ajoutant "import { HttpClient } from "@angular/common/http";" en haut de votre fichier hobby.service.ts
      • Modifiez le code de la classe du service comme suit :

        export class HobbyService {
          constructor(private http: HttpClient) {}


          getHobbies(): Promise<any> {
            // on va chercher par GET le fichier JSON sur un REST endpoint
            return this.http.get(this.url).toPromise();

          }
        }

      • Modifiez le fichier app.module.ts pour rajouter le module "HttpClient" à l'application: import { HttpClientModule } from "@angular/common/http";
        import { HobbyService } from "./hobby.service";

        et ajoutez aussi le service HobbyService et ml module HttpClient e aussi à la directive @NgModule:

        @NgModule({
          declarations: [AppComponent, UsernameComponent],
          imports: [BrowserModule, FormsModule, HttpClientModule],
          providers: [HobbyService],
          bootstrap: [AppComponent]
        })
         
      • Enfin, dans le composant principal app.component.ts, qui affiche les hobbies, il faut aussi importer HobbyService:
        import { HobbyService } from './hobby.service';

        "Injecter le service" via le constructeur :

        // On "injecte le service" qui servira par la suite à
          // récupérer des données sur le Web
          constructor(private hobbyService: HobbyService) {}

        Indiquer qu'on va charger les hobbies avant d'afficher la liste :

        // Appelé lorsque le composant est créé
          ngOnInit(): void {
            this.getHobbies();
          }

        et voici la méthode getHobbies() qui utilise le service, l'ajouter aussi au fichier

        getHobbies() {
            this.hobbyService.getHobbies().then(response => {
              this.hobbies = response.data;
            });
         
      •  
    • Correction de cet exercice

2 - Utiliser un routeur

Angular vient avec un routeur intégré (contrairement à VueJS et React).

Création de route

Et on va modifier le template du composant App en rajoutant des liens de navigation avec routerLink:
   

<h1><nav><a routerLink = "/home">Home</a><arouterLink = "/hobbies">Hobbies</a></nav></h1>

Vous devrez créer un composant Home très simple....

On va aussi initialiser les routes dans le fichier app.module.ts. Placez ce code avant la déclaration de @NgModule dans app.module.ts :

 const routes: Routes = [
 // home page
 {path:'', component:Home},  {path:'home', component:Home},
{path:'hobbies', component:ListeHobbiesComponent}
];

Modifiez également la propriété "imports" du module:

imports: [
 BrowserModule,
 FormsModule,
 HttpClientModule,
 RouterModule.forRoot(routes)
 ]

Et mettez à jour les imports en tête du fichier :

import {Routes, RouterModule} from '@angular/router';

Tant qu'à faire : modifiez le fichier styles.css global en ajoutant :

* {
    font-family:"Andale Mono", sans-serif;
}

 Voilà, si vous ne vous êtes pas trompés, vous devriez avoir en haut de la page web qui s'affiche un lien "Gestionnaire de projets", si vous cliquez dessus, ça doit afficher l'url "http://localhost:4200/home".

<div>
...
</h1>
 <router-outlet></router-outlet>
</div>

CORRECTION ANGULAR avec Hobbies distants dans un service et utilisation d'un router. Pour faire tourner : désarchiver, aller dans le répertoire, faire "npm install", puis "ng serve --open". Cliquer sur "Home" ou "Hobbies" pour que l'affichage change...