Créer une "application web " avec Meteor - Brouillon v230714
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
Ce texte est sous licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International. Pour accéder à une copie de cette licence, merci de vous rendre à l'adresse suivante http://creativecommons.org/licenses/by- sa/4.0/ ou envoyez un courrier à Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. Le titulaire des droits autorise toute utilisation de l’œuvre originale (y compris à des fins commerciales) ainsi que la création d’œuvres dérivées, à condition qu’elles soient distribuées sous une licence identique à celle qui régit l’œuvre originale. 2
Notes de l'auteur Ce document est à l'origine destiné aux élèves de seconde, du lycée G Fichet de Bonneville (Haute-Savoie), qui ont choisi de suivre l'enseignement d'exploration PSN (Pratique Scientifique et Numérique). Plus généralement il est utilisable par toutes personnes désirant apprendre à développer des applications web. Des connaissances en JavaScript, HTML et CSS sont indispensables avant d'aborder Meteor (voir, par exemple, les 18 activités « JavaScript, HTML et CSS » que j'ai rédigées pour les élèves). De plus, des connaissances "de base" sur la librairie jQuery seront un plus, mais ne sont pas indispensables. Vous trouverez en annexe une digression quelque peu "théorique" sur la notion de client-serveur. Je conseille aux personnes étant totalement novices en la matière de lire cette annexe avant de commencer les activités. L'annexe 2 est consacrée au CSS (à la mise en page plus exactement) Ce document n'a pas la prétention d'être la « bible » de Meteor (n'oubliez pas qu'il s'adresse à des élèves ayant une pratique limitée de la programmation), il a été conçu pour travailler « en collaboration » avec l'enseignant (certaines parties ne sont pas détaillées, les enseignants devront adapter leurs explications en fonction des contraintes locales (OS installé, possibilité d'installer des logiciels sur les machines......)). David Roche 3
Activité 1 Présentation et installation de Meteor Mais qu'est-ce que Meteor ? Meteor est une plateforme open-source qui permet de développer très rapidement des applications web complètes (site officiel : https://www.meteor.com/). Meteor gère à la fois le côté client et le côté serveur, y compris le stockage des données dans une base de données (si ces notions de client-serveur et de base de données vous sont inconnues, consulter l'annexe 1 de ce document). Meteor s'appuie sur nodeJS et mongoDB (pour en savoir plus sur nodeJS et mongoDB voir, là aussi, l'annexe 1) Installation Au moment où ces lignes sont écrites, Meteor n'est pas supporté par Windows officiellement. Si vous n'avez pas la possibilité d'installer un environnement GNU/linux, je vous conseille d'utiliser une machine virtuelle. L'installation d'une telle machine sortant du cadre de ce document, je vous laisse faire les recherches nécessaires sur internet. Voici la procédure à suivre sur un système de type "Ubuntu" ou "Mint" : À faire vous-même Commencer par installer curl (si nécessaire) en tapant dans une console : sudo apt-get install curl Une fois curl installé, toujours dans une console tapez : curl https://install.meteor.com/ | sh Après une attente plus au moins longue, Meteor devrait maintenant être installé sur votre ordinateur. Avant de commencer à utiliser Meteor, nous allons installer Meteorite. Meteorite vous permettra d'installer très simplement des extensions qui fonctionneront avec Meteor : Installer tout d'abord nodejs : sudo apt-get install nodejs-legacy Si nécessaire, installer npm : sudo apt-get install npm Enfin, vous pouvez installer Meteorite : sudo -H npm install -g meteorite Première Application À faire vous-même Vous êtes prêt à créer votre première application Meteor : Dans votre répertoire personnel, toujours à l'aide de la console, créer un nouveau répertoire (ce répertoire vous servira de répertoire de travail) : mkdir mesAppMeteor Placez-vous dans ce répertoire : cd mesAppMeteor et créer votre première application : mrt create monApp_1 4
Pour vérifier que tout à bien fonctionné : placez-vous dans le répertoire qui vient d'être créé : cd monApp_1 et taper : mrt Vous devriez avoir à l'écran : Sans fermer la console, ouvrir un navigateur et taper dans la barre d'adresse : http://localhost:3000/ Si tout a fonctionné, vous devriez avoir dans votre navigateur le résultat suivant : http://localhost:3000/ ? Dans l'annexe 1 de ce document, j'insiste sur le fait que la consultation d'un site internet est un échange de données entre 2 ordinateurs distants (un client et un serveur), or, ici, nous n'utilisons qu'un ordinateur ? Dans toute la phase de développement, il est tout à fait possible d'utiliser un seul ordinateur qui jouera à la fois (et en même temps) le rôle du client et le rôle serveur. L'exécution, dans la console, de la commande mrt « démarre » le serveur, une fois le serveur démarré il « attend » les requêtes HTTP en provenance d'un client. Le navigateur web va envoyer ces requêtes au serveur. Mais comment entrer en communication avec le serveur ? Il suffit d'utiliser une adresse un peu spéciale : localhost (localhost indique au navigateur web que le serveur se trouve sur la même machine que lui). Le ": 3000" définie le port utilisé par le serveur. Plusieurs applications peuvent utiliser la même connexion réseau à condition de ne pas utiliser le même port (on parle aussi de socket). Ici notre serveur « écoute » et « attend » une requête HTTP sur le port 3000. Mettre son application en ligne Il est possible de rendre son application disponible sur internet (publier son application). Il suffira, depuis la console (et depuis le répertoire de l'application que vous voulez publier de taper : "mrt deploy monApp.meteor.com" (remplacez 5
"monApp" par le nom de votre choix). Le système vous demandera votre adresse email, et c'est tout...(vous aurez aussi à vous connecter pour configurer votre compte). Votre application sera disponible en tapant depuis un navigateur : "http://monApp.meteor.com". Pour effacer une application : placez-vous dans la console et tapez "mrt deploy - -delete monApp.meteor.com" (toujours, évidemment, en remplaçant "monApp" par le nom de votre application). Attention, cet hébergement est gratuit, mais il n'est pas prévu pour héberger des applications "en production" (des applications qui verront plusieurs dizaines de connexions par minute). Ce système est proposé juste à des fins de test. Il existe d'autres solutions pour mettre votre application en ligne (souvent payantes), mais cela sort du cadre de ces activités. 6
Activité 2 Création des dossiers et structure d'une application Si vous parcourez le dossier monApp_1, vous allez trouver plusieurs fichiers dont monApp_1.css, monApp_1.html et monApp_1.js. Ces fichiers ont été générés automatiquement lors de la création de l'application (utilisation de la commande mrt create monApp_1). Pour différentes raisons que je ne détaillerai pas maintenant, nous n'allons pas utiliser ces fichiers, vous pouvez donc les effacer (attention de ne pas effacer le fichier smart.json et éventuellement le fichier smart.lock. Sachez aussi que le dossier monApp_1 contient un dossier caché .meteor : vous ne devez jamais "toucher" à ce dossier sous peine d'un dysfonctionnement définitif de votre application). À faire vous-même Nous allons créer une structure un peu plus complexe. Toujours en vous plaçant dans le dossier monApp_1, créez les dossiers suivants : - client - server - public Quelques explications sur la création de ces dossiers : Meteor gère à la fois le côté client et le côté serveur, tous les fichiers se trouvant dans le dossier "client" ne seront "exécutés" que par le client, de la même manière, tous les fichiers se trouvant dans le dossier "server" ne pourront être utilisé que du côté serveur. Tous les autres fichiers, c'est-à-dire ceux qui ne se trouvent ni dans le répertoire "client", ni dans le répertoire "server", pourront à la fois être utilisés côté client et côté serveur. Je précise quand même, pour que les choses soient bien claires dans votre esprit, qu’au départ (juste avant la 1ère requête effectuée par le client), tous les fichiers se trouvent sur le serveur, mais les fichiers se trouvant dans le répertoire client sont destinés à être envoyé au client (au moyen de requêtes HTTP), le serveur ne les exécutera jamais. En revanche les fichiers se trouvant dans le répertoire "server" ne feront jamais le "voyage" jusqu'au client, ils sont strictement réservés au serveur. À faire vous-même Placez-vous dans le répertoire client et créez les dossiers suivants : - css - JavaScript - templates Toujours dans le répertoire "client", créez un fichier main.html De la même façon, créez un fichier main.css dans le dossier "css" et un fichier main.js dans le dossier "JavaScript". Structure à mettre en place pour toute nouvelle application Meteor Voilà, la structure de base de notre application est maintenant à place. Pour chaque nouvelle application Meteor, il vous faudra suivre la même démarche : • Création de l'application à l'aide de la commande mrt create monApp (si vous avez choisi monApp comme nom pour votre application). • Effacer les fichiers monApp.js, monApp.html et monApp.css créés par défaut par meteor dans le répertoire monApp (toujours si vous avez choisi monApp comme nom pour votre application !). • Créer les répertoires "client", "server" et "public" dans le répertoire monApp • Créer les répertoires "css", "JavaScript" et "template" ainsi que le fichier main.html dans le répertoire client • Créer un fichier main.js dans le répertoire "JavaScript" et un fichier main.css dans le répertoire "css" 7
Activité 3 Première application, première approche de la "philosophie" de Meteor À faire vous-même Créez une application nommée app_01 et mettez en place la structure vue ci-dessus. Éditez le fichier main.html App01 App01 Bonjour et bienvenu dans Meteor Éditez le fichier main.js alert('Le JavaScript fonctionne aussi !') Éditez le fichier main.css h1{ text-align: center; } Lancez cette application en ouvrant la console, en vous plaçant dans le dossier app_01 et en tapant mrt au niveau de l'invite de commande. Tout fonctionne : le HTML (notre page s'affiche bien), le JavaScript (nous avons bien apparition de la "boite alert") et le CSS (notre titre h1 se trouve bien au centre de l'écran). Pourtant, "logiquement" tout cela ne devrait pas fonctionner : • le fichier HTML n'est pas complet (il manque le doctype, la balise meta et la balise html) • on ne trouve aucune référence au fichier main.js dans le html (par exemple un "") • toujours dans le html, on ne trouve aucune référence au fichier main.css (par exemple un "") Et pourtant tout cela fonctionne : c'est la "magie" de Meteor (et vous n’êtes pas au bout de vos surprises !) 8
Activité 4 Introduction aux templates À faire vous-même Créez une nouvelle application app_02 main.html App02 App02 Bonjour vous allez voir ci-dessous un template {{>monTemplate}} Avez-vous vu le template ? main.css reste inchangé par rapport à l'application précédente et main.js doit être vide. Créez un fichier que vous nommerez templates.html et placez-le dans le répertoire template (le répertoire template se trouve dans le dossier client). templates.html Voici le template Testez cette application, vous devriez obtenir ceci : Vous avez, je pense, compris la notion de template : Dans Meteor, la gestion des templates est basée sur le moteur de template handlebars (http://handlebarsjs.com/). Au moment de l'affichage de la page "{{>monTemplate}} " sera remplacé par ce qui se trouve dans la balise "à". La balise template ( ) peut se trouver dans le même fichier que la double accolade ({{>monTemplate}}) ou, comme dans notre exemple dans 2 fichiers différents (le fichier main.html et le fichier templates.html). Vous pouvez choisir le nom que vous voulez pour le template : par exemple, nous pourrons avoir "{{>toto}} " et " ". Il est possible d'avoir plusieurs templates dans une même page. À faire vous-même Créez une application app_03. Le fichier main.html devra contenir 2 templates. Le code de ces 2 templates devra se trouver dans le fichier templates.html. Pour l'instant, l'intérêt des templates ne saute pas aux yeux, pourtant, comme nous allons le voir dans la suite de ce document, ce sont des outils extrêmement puissants. 9
Activité 5 les templates et les contrôleurs Un template est très souvent couplé avec contrôleur. Un contrôleur est une méthode JavaScript associée à un template. Les contrôleurs vont permettre de rendre les templates dynamiques. Voici un premier exemple : À faire vous-même Créez une application app_04 Complétez les différents fichiers comme suit : main.html App04 App04 {{>monTemplate}} template.html (fichier se trouvant dans le dossier templates) Voici mon nom : {{nom}} controller.js (créez ce fichier dans le répertoire JavaScript) Template.monTemplate.helpers({ nom:function(){ return "toto"; } }); Par ailleurs, pour cet exemple et pour tous les exemples suivants : • vous pourrez supprimer le fichier main.js • le fichier main.css restera inchangé (sauf précision contraire). Voici le résultat que vous devriez obtenir : Le fichier main.html ne comporte aucune nouveauté, intéressons-nous donc au fichier template.html et controller.js : Le fichier template.html comporte une nouveauté le "{{nom}}" : vous reconnaissez les doubles accolades déjà vues précédemment, mais notez cette fois-ci, l'absence du signe > (comme dans "{{>monTemplate}). "{{nom}}" représente une variable, meteor nous permet donc d'introduire des variables dans les templates HTML (vous commencez à comprendre l’intérêt des templates par rapport à du HTML "classique"). Mais où définit-on la valeur contenue dans cette variable ? Pour répondre à cette question, il va falloir nous intéresser au contenu du fichier controller.js : "Template.monTemplate.helpers" d'un point de vue "purement JavaScript" nous avons ici affaire à une méthode (la méthode "helpers" appartient à l'objet "monTemplate" qui est lui-même un attribut de l'objet "Template"). C'est cette méthode qui nous permettra d'interagir avec le template "monTemplate" (de rendre ce template dynamique) : cette méthode sera le contrôleur du template "monTemplate". La méthode "helpers" prend en paramètre un objet JavaScript : "{nom:function(){return "toto";}". Dans notre exemple, cet objet n'a qu'un seul attribut, l'attribut "nom". Cet attribut est une fonction (donc en faite une méthode puisque c'est une fonction associée à un objet), qui ne fait qu'une seule, renvoyer la chaîne de caractère " toto". Le "{nom:function(){return "toto}";" est donc équivalent à un "{nom:"toto";}" (nous avons vu dans les activités consacrées à l'apprentissage de la programmation avec JavaScript qu'il suffit de remplacer la fonction par la 10
valeur qu'elle retourne (grâce au mot clé return) pour avoir une idée du résultat de l'exécution de cette fonction). Vous devez savoir que nous aurions très bien pu écrire directement "{nom:"toto";}", cela aurait aussi bien fonctionné. Mais par anticipation de ce que nous verrons plus loin dans ce document, j'ai choisi de tout de suite vous présenter la version "{nom:function(){return "toto";}". Pour résumer, nous avons attribué la valeur "toto" à la variable nom (dans le fichier controller.js grâce à la méthode "Template.monTemplate.helpers", puis nous avons utilisé cette variable dans le template "monTemplate" (fichier template.html) avec le "{{nom}}"). Notez que vous pourrez aussi rencontrer une écriture un peu différente : Template.monTemplate.nom=function(){return "toto";}; Cette seconde façon d'écrire la méthode "helpers" est totalement équivalente à celle que nous avons vu plus haut, c'est juste un "raccourci". À faire vous-même En vous basant sur l'application app_05 créez une application app_06 qui permettra d'afficher : Voici mon nom : Toto Voici mon prénom : Titi Attention les chaînes de caractères Toto et Titi ne devront pas être "codées" directement dans le template (fichier template.html). Utilisation des objets JavaScript Au lieu de renvoyer une simple variable, la méthode "helpers" peut aussi renvoyer un objet JavaScript. Si vous avez besoin de vous rafraîchir la mémoire à propos des objets en JavaScript, je ne serai trop vous conseiller de revoir l'activité 14 du document "Activités JavaScript, HTML et CSS". À faire vous-même Créez et étudiez cette application (app_06) main.html App06 App06 {{>monTemplate}} template.html Voici mon nom : {{monPerso.nom}} Voici mon prénom : {{monPerso.prenom}} Voici mon âge : {{monPerso.age}} controller.js var perso={ nom:"toto", prenom:"titi", age:15 } Template.monTemplate.helpers({ monPerso:function(){ 11
return perso; } }); Vous pouvez constater que la méthode "helpers" prend toujours un objet en paramètre ({ monPerso:function() { return perso; } ). Mais cette fois l'attribut "monPerso" est une méthode qui ne renvoie pas une "simple" variable comme dans l'application app_04, mais renvoie un objet JavaScript. Cet objet JavaScript a été défini au début du fichier controller.js (var perso={ nom:"toto", prenom:"titi", age:15 }). Dans le fichier template.html on a maintenant "{{monPerso.nom}}" (l'attribut nom de l'objet monPerso) à la place du simple "{{nom}}" de l'application app_04. Il est possible de simplifier l'écriture du template comme suit : template.html {{#with monPerso}} Voici mon nom : {{nom}} Voici mon prénom : {{prenom}} Voici mon âge : {{âge}} {{/with}} Toutes les doubles accolades se trouvant entre le "{{#with monPerso}} " et le "{{/with}} " concerneront l'objet monPerso. Le "Voici mon nom : {{nom}} " correspondra bien à un "Voici mon nom : {{monPerso.nom}} ".... même chose pour les autres attributs (prenom et âge). Ici aussi, cela permet d'alléger l'écriture. À faire vous-même En partant de l'objet suivant : var fiche={ nom : "Dupond", prenom : "Michel", dateNaissance : "17/06/1998", adresse : "45 rue de la monté" } et en vous basant sur l'application app_06, créez un application app_07 qui affichera dans votre navigateur les informations suivantes : Nom : Dupond Prénom : Michel Date de Naissance : 17/06/1998 Adresse : 45 rue de la montée Vous veillerez à utiliser le couple "{{#with .....}}...{{/with}}". 12
Activité 6 Les boucles et les templates Les boucles et les tableaux d'objets Imaginons que nous voulions afficher non pas une fiche "d'identité" mais trois. Ces trois fiches qui seront toujours "stockée" sous forme d'objets JavaScript, pourraient prendre cette forme : var fiche1={ nom : "Dupond", prenom : "Michel", dateNaissance : "17/06/1998" } var fiche2={ nom : "Durand", prenom : "Albert", dateNaissance : "07/02/1991" } var fiche3={ nom : "Dupuis", prenom : "Christelle", dateNaissance : "28/02/2001" } Par souci de simplification nous allons stocker nos fiches (et donc nos objets JavaScript) dans un tableau : var tabFiche=[ {nom : "Dupond", prenom : "Michel", dateNaissance : "17/06/1998"}, {nom : "Durand", prenom : "Albert", dateNaissance : "07/02/1991"}, {nom : "Dupuis", prenom : "Christelle", dateNaissance : "28/02/2001"} ] Prenez bien garde à la position des virgules : il y a des virgules entre les attributs d'un objet (sauf après le dernier attribut) et des virgules entre les objets (sauf après le dernier objet). Comment accéder aux objets contenus dans le tableau ? Les objets stockés dans le tableau tabFiche n'ont plus de nom, nous ne pouvons donc plus écrire "fiche1.nom" (qui est égal Dupond). Mais le premier objet (la première fiche) est le premier élément du tableau tabFiche, il possède donc l'indice de position 0, le deuxième objet est le second élément du tableau, il possède donc l'indice de position 1.... Donc à quoi correspond tabFiche[1] ? Au deuxième objet du tableau ! Et donc, à quoi correspond tabFiche[0].nom ? tabFiche[0] correspond au premier objet du tableau et donc tabFiche[0].nom est égal à Dupond ! En JavaScript "classique" il est donc relativement facile d'afficher toutes les fiches présentes dans le tableau, il suffit d'utiliser une boucle for : for (var i=0 ; i
Les boucles et les templates Il est très facile de réaliser la même chose avec meteor. La boucle ne sera pas "codée" en JavaScript, mais directement intégrée au template. Étudiez et testez cet exemple : À faire vous-même Créez et étudiez cette application (app_08) main.html App08 App08 {{>monTemplate}} template.html {{#each mesFiches}} Nom : {{nom}} Prénom : {{prenom}} Date de naissance : {{dateNaissance}} {{/each}} controller.js var tabFiche=[ {nom : "Dupond", prenom : "Michel", dateNaissance : "17/06/1998"}, {nom : "Durand", prenom : "Albert", dateNaissance : "07/02/1991"}, {nom : "Dupuis", prenom : "Christelle", dateNaissance : "28/02/2001"} ] Template.monTemplate.helpers({ mesFiches:function(){ return tabFiche; } }); Comme vous pouvez le constater, la méthode "helpers" a pour paramètre un objet qui contient une méthode qui renvoie le tableau "tabFiche". Dans le template, tout ce qui se trouve entre "{{#each mesFiches}} " et "{{/each}} " correspond au code qui sera dupliqué le nombre de fois nécessaire afin de pouvoir "parcourir" l'ensemble des objets contenu dans le tableau. Vous devez bien comprendre que "{{nom}}" correspond bien à l'attribut nom des objets contenus dans le tableau. À faire vous-même Créer une application (app_09) qui permettra d'afficher les informations contenues dans le tableau suivant : tabVoitures=[ {marque : "Renault", couleur : "rouge", annee : "2012"}, 14
{marque : "Fiat", couleur : "verte", annee : "2011"}, {marque : "Peugeot", couleur : "jaune", annee : "2010"} ] Vous devrez réinvestir tout ce que nous venons de voir. Un exemple un peu plus complexe Il est possible d'imbriquer les templates : À faire vous-même Étudiez et testez cette application (app_10) : main.html App10 App10 {{>monTemplate}} template.html {{#each mesFruits}} {{>monFruit}} {{/each}} {{nom}} controller.js var mesFruitsTab=[{nom:"banane"},{nom:"pomme"},{nom:"ananas"},{nom:"pêche"}, {nom:"fraise"}]; Template.monTemplate.helpers({ mesFruits:function(){ return mesFruitsTab; } }); "mesFruitsTab" est un tableau d'objets (cela correspond à ce que nous verrons dans la grande majorité des cas par la suite), chaque objet ne contient qu'un attribut : "nom". Le "helpers" "mesFruits" du template "monTemplate" renvoie ce tableau d'objets. Grâce à la structure de type "{{#each...}}", le template "monFruit" est "exécuté" pour chaque objet contenu dans le tableau. Nous aurons donc ici l’enchaînement de 5 balises "", "{{nom}}" étant successivement remplacé par banane, pomme, ananas et afin pêche. Dans la suite, nous privilégierons cette structure "{{#each monHelper}}{{>monTemplate}}{{/each}}" couplée avec un tableau d'objets JavaScript (qui plus tard, sera issu d'une base de données), il est donc important de bien assimiler cet exemple. 15
Activité 7 Les événements Afin de favoriser les interactions entre l'application et les utilisateurs, meteor propose un système de gestion d'événement. Par exemple, si vous placez sur votre page un bouton destiné à valider un formulaire, meteor vous permettra de gérer assez facilement les données issues du formulaire. Étudions plus précisément cet exemple. À faire vous-même Étudiez et testez cette application (app_11) : Attention cet exemple utilise la bibliothèque jQuery, vous devez donc l'installez afin de pouvoir l'utiliser avec Meteor. Dans la console, placez-vous dans le répertoire de votre projet (par exemple ici app_11) et tapez : mrt add jquery main.html App11 App11 {{>formulaire}} template.html Nom Prénom controller.js Template.formulaire.events({ 'submit #monFormulaire': function(e){ e.preventDefault(); nomUser=$('#nom').val(); prenomUser=$('#prenom').val(); $('#nom').val(''); $('#prenom').val(''); $('#info').append('Bonjour '+prenomUser+' '+nomUser+'') } }) Rien de nouveau pour main.html et template.html (à part le formulaire), concentrons-nous donc sur controller.js : Pas de "helpers" ici, en revanche nous avons une méthode "events". Cette méthode "events" prend en paramètre un objet JavaScript. Cet objet possède un attribut : "'submit #monFormulaire'". Cet attribut nous informe qu'en cas de soumission ("submit") du formulaire ayant pour identifiant "monFormulaire", la fonction "function(e)" devra être exécutée. Voici, dans notre exemple, le contenu de cette fonction : "e.preventDefault(); nomUser=$('#nom').val(); prenomUser=$('#prenom').val(); $('#nom').val(''); $('#prenom').val(''); $('#info').append('Bonjour '+prenomUser+' '+nomUser+'')" La première ligne ("e.preventDefault()"), empêche la soumission "classique" du formulaire, je ne vais pas m'étendre sur cette question, mettez cette ligne en début de fonction si vous ne voulez pas avoir de mauvaises surprises ! 16
Ensuite, nous utilisons la bibliothèque jQuery : "nomUser=$('#nom').val(); " : permet de récupérer le contenu du champ du formulaire ayant l'id nom et range ce contenu dans la variable nomUser. "prenomUser=$('#prenom').val(); " : même chose que ci-dessus, mais avec le prénom "$('#nom').val(''); " : vide le champ du formulaire ayant pour id nom "$('#prenom').val(''); " : même chose que ci-dessus, mais pour le prénom "$('#info').append('Bonjour '+prenomUser+' '+nomUser+'')" : permet d'ajouter une balise p dans la balise div ayant pour id info (voir le template). Cette balise p aura pour contenu "Bonjour '+prenomUser+' '+nomUser+'" où "prenomUser" et "nomUser" auront été remplacé par leurs valeurs. Je ne m'attarde pas plus sur cette ligne, car dans un avenir très proche nous n'aurons plus à utiliser la méthode "append" de jQuery, nous utiliserons plutôt la méthode "helpers" de meteor. 17
Activité 8 Les collections Nous allons ici aborder, sans doute, la partie la plus importante de cette série d'activité : les collections. La notion de collection est, dans meteor, directement lié aux bases de données, donc au stockage des informations. En effet, jusqu'à présent, un simple redémarrage du serveur faisait perdre les données saisies par l'utilisateur (par exemple dans l'application "app_11"). Les collections vont nous permettre de stocker les données et de pouvoir les réutiliser. Qui dit base de données, dit requête, mais qu'est-ce qu’une requête ? Les requêtes sont, en quelque sorte, des "ordres" donnés à la base de données. Les requêtes peuvent avoir trois buts : la lecture des informations stockées dans la base de données, l'écriture d'informations dans la base de données ou encore la suppression d'informations stockées dans la base de données. Mais sous quelles formes sont stockées les informations dans la base de données ? Quand vous allez effectuer une requête pour ajouter des données à une collection (donc, écrire dans une base de données), vous allez devoir envoyer les données sous forme d'objet JavaScript. Si par exemple vous désirez stocker une fiche de renseignement qui comporte un nom (Toto) et un prénom (Titi), vous devrez tout d'abord créer l'objet JavaScript suivant : fiche = {nom : 'Toto', prenom : 'Titi'}. Partons maintenant du principe que nous voulons stocker cette fiche de renseignement dans un collection ayant pour nom Fiches (une collection peut accueillir un très grand nombre de fiches), il nous faudra écrire la requête suivante : "Fiches.insert(fiche)". Si maintenant nous désirons "récupérer" toutes les fiches contenues dans la collection "Fiches", il nous suffira d'écrire la requête suivante : "Fiches.find()" Qu'est-ce qui est renvoyé par la base de données ? La base de données renvoie un tableau d'objet JavaScript (dans le cas d'une requête "Fiches.find()", ce tableau contiendra tous les objets JavaScript contenus dans la collection "Fiches"). Pour traiter ce tableau d'objet, il suffira d'appliquer les méthodes déjà vues dans l'exemple "app_10". N.B : Il est tout à fait possible d'effectuer des requêtes plus complexes, par exemple : "récupérer les fiches des personnes ayant pour prénom Titi", mais nous reviendrons sur ces requêtes complexes un peu plus tard, contentons-nous pour l'instant de récupérer toutes les fiches. À faire vous-même Afin d'initier la création de la collection "Fiches" (et donc de la base de données qui va avec), il est nécessaire de créer un nouveau dossier "collections". Ce dossier devra se trouver "à côté" des dossiers existants ("client", "public" et "server"). Vous remarquerez sans doute que ce dossier "collections" ne se trouvant ni dans le dossier "server" ni dans le dossier "client" sera à la fois accessible du côté client et du côté serveur. Ceci est indispensable, car, sans vouloir trop rentrer dans le fonctionnement interne de meteor, il faut que vous sachiez que si la base de données "principale" se trouve bien côté serveur, chaque client possède une "copie" de cette base de données afin de rendre les interactions "client-base de données" beaucoup plus "rapide". Toute la "magie" de meteor se trouvant dans le fait que ces copies côté client sont, en permanence, mises à jour par le serveur. À faire vous-même Créez un fichier "mesFiches.js" et placez-le dans le dossier "collections" À faire vous-même Nous allons maintenant créer une application (app_12) qui utilisera une collection. Avant de nous intéresser au code de cette application, quelques mots sur son principe : L'utilisateur aura à sa disposition un formulaire pour saisir un nom et un prénom (une nouvelle fiche). La validation de ce formulaire entraînera une série d’événements : création d'un objet JavaScript "perso" qui contiendra le nom et le prénom saisis par l'utilisateur. Cet objet "perso" sera placé dans la collection "Fiches". En vous aidant des informations fournies ci-dessus, étudiez et testez cette application (app_12) 18
main.html App12 App12 {{>formulaire}} {{>liste}} template.html Nom Prénom {{#each mesFiches}} {{>fiche}} {{/each}} {{#if nomUser}} Nom : {{nomUser}} Prénom : {{prenomUser}} {{/if}} controller.js Template.formulaire.events({ 'submit #monFormulaire': function(e){ e.preventDefault(); var perso={nomUser:$('#nom').val(),prenomUser:$('#prenom').val()} $('#nom').val(''); $('#prenom').val(''); Meteor.call('ficheCollIns',perso); } }); Template.liste.helpers({ mesFiches : function(){ var mesFi=Fiches.find(); return mesFi; } }); mesFiches.js (dans le dossier collections) Fiches = new Meteor.Collection('fiches'); Meteor.methods({ ficheCollIns:function(p){ Fiches.insert(p) } }); Quelques explications : • Petite nouveauté dans le fichier "template.html" : la présence de "{{#if nomUser}}" et de "{{/if}}". Vous aurez peut-être compris par vous-même que ce qui se trouve entre le "{{#if nomUser}}" et le "{{/if}}" ne sera affiché que si "nomUser" existe. • La variable "mesFi" du fichier "controller.js" contient le tableau contenant lui même tous les objets de la 19
collection "Fiches". Nous renvoyons donc avec le "return mesFi; " un tableau d'objet, comme dans l'exemple 10 (app_10) (il aurait été possible d'écrire directement "return Fiches.find(); "). Le traitement au niveau du template (fichier "template.html") a aussi été étudié dans l'exemple 10. • Attardons-nous sur la méthode "Template.formulaire.events" : cette méthode ressemble beaucoup à ce que l'on a déjà vu dans l'exemple 11 (app_11) (gestion des données saisies dans le formulaire, création d'un objet JavaScript "perso"....). Seule la fin diffère un peu avec le "Meteor.call('ficheCollIns',perso);". Cette méthode "Meteor.call" prend 2 paramètres : le nom d'une méthode à exécuter (ici "'ficheCollIns'") et le paramètre à faire passer (ici l'objet "perso" qui vient d'être "créé" juste au-dessus). Mais où se trouve cette méthode "ficheCollIns" qui doit être exécutée ? De façon générale, toutes les méthodes appelées par la méthode "Meteor.call" devront se trouver dans la méthode "Meteor.methods" (vous trouverez cette méthode dans le fichier "mesFiches.js"). La méthode "Meteor.methods" prend un unique paramètre : un objet JavaScript. C'est dans cet objet JavaScript que nous avons "placé" la méthode "ficheCollIns". Dans notre exemple, la méthode "ficheCollIns" a pour paramètre "fiche". Vous avez peut-être déjà compris que "fiche" correspond au deuxième paramètre de la méthode "Meteor.call", c'est-à-dire à l'objet JavaScript placé dans "perso". Le "Fiches.insert(fiche)" que l'on trouve dans la méthode "ficheCollIns" permet donc de ranger la nouvelle fiche, qui vient d'être saisie par l'utilisateur par l'intermédiaire du formulaire, dans la collection "Fiches". • Dans le fichier "mesFiches.js" j'attire votre attention sur la ligne "Fiches = new Meteor.Collection('fiches');". C'est cette ligne qui permet d'initialiser la collection "Fiches", il est donc très important de ne pas l'oublier. • Vous avez sans doute remarqué qu'une nouvelle fiche qui vient d'être saisie par l'intermédiaire du formulaire se retrouve immédiatement affichée. La collection est donc "surveillée" en permanence et le moindre changement est immédiatement répercuté au niveau de tous les éléments qui utilisent cette collection (dans notre cas le template "fiches" Tout cela doit vous paraître bien complexe, n'hésitez donc pas à poser des questions. À faire vous-même Lancez l'application "app_12" et ouvrez 2 fenêtres de votre navigateur préféré. Vous pouvez constater qu'une nouvelle fiche saisie dans une des 2 fenêtres est immédiatement affichée dans les 2 fenêtres. Ce qui est vrai, en local, dans nos 2 fenêtres serait évidemment vrai, pour tous les clients connectés à notre application, même s'ils se trouvent à des milliers de kilomètres les un des autres. Il est possible d'effacer tout le contenu des collections utilisées dans votre application avec une simple ligne de commande dans la console : "mrt reset" 20
À faire vous-même Toujours en utilisant l'exemple 12 (app_12), supprimer toutes les données contenues dans la collection " Fiches" en utilisant la ligne de commande "mrt reset". À faire vous-même Vous allez créer une nouvelle application (app_13) en vous basant sur l'exemple 12 (app_12). Cette nouvelle application devra proposer à l'utilisateur de saisir un nom, un prénom et le nom d'un fichier "photo". Chaque fiche devra contenir les informations saisies par l'utilisateur et afficher la photo (voir la capture d'écran ci-dessous). Les photos seront placées dans le répertoire "public" de votre application meteor. Aucun système d'upload (client vers serveur) des photos n'est demandé ici. Si aucun nom de photo n'a été saisi pour une fiche donnée, une photo "par défaut" devra tout de même être affichée. 21
Activité 9 Construire un menu avec Bootstrap Cette activité ne sera pas directement consacrée à meteor (même si nous allons tout de même l'utiliser). En effet nous allons nous intéresser au style et à la mise en page d'une application web. Vous devez sans doute déjà savoir que le style et la mise en page d'un site internet se gèrent grâce au CSS (voir l'annexe 2 pour plus d'information sur le CSS), mais il est, pour des non-spécialistes, parfois difficile de créer le style et la mise en page d'un site en partant de zéro. C'est pour cela que Bootstrap existe ! D'après Wikipedia : Bootstrap est une collection d'outils utile à la création de sites web et applications web. C'est un ensemble qui contient des codes HTML et CSS, des formulaires, boutons, outils de navigation et autres éléments interactifs, ainsi que des extensions JavaScript en option. Nous n'allons, dans cette activité, explorer toutes les possibilités offertes par Bootstrap, nous allons juste apprendre à réaliser un menu. Mais je vous invite très fortement à visiter le site http://getbootstrap.com/ afin de vous familiariser avec ce magnifique outil qui vous sera très utile si vous ne voulez construire de "belles" applications web sans trop "vous prendre la tête" avec le CSS. Attention : si vous recherchez des ressources pour apprendre à utiliser Bootstrap sur internet, il faut bien que vous recherchiez des tutoriaux sur Bootstrap 3 (la version 2 est incompatible avec la version 3). À faire vous-même Créez une nouvelle application meteor (app_14). Installez Bootstrap grâce à meteorite à l'aide de la console, en vous plaçant dans le répertoire app_14 qui vient d'être créé et en tapant : mrt add bootstrap-3 À faire vous-même Saisissez, étudiez et testez les codes suivants (app_14) main.html App14 {{>menu}} template.html App 14 Accueil Page 1 Page 2 Pas de fichier JavaScript pour cette application 14 Rien à ajouter sur cet exemple qui était juste là pour vous montrer qu'il est très facile de créer un menu en utilisant Bootstrap. Notez tout de même que pour l'instant les liens pointent "dans le vide" (" href="#""). Encore une fois, n'hésitez pas à vous renseigner sur les possibilités offertes par Bootstrap. Pour vous "obliger" à travailler sur Bootstrap, je continuerai à l'utiliser dans les prochaines activités. 22
Activité 10 Créer une application multipage avec iron-router Dans l'activité 9 nous avons créé un menu, dans cette activité nous allons utiliser ce menu afin de mettre en place un système de navigation. Nous partirons donc du principe que notre site (ou application) web est composé de plusieurs pages. À faire vous-même Créez une nouvelle application (app_15). Installez iron-router grâce à meteorite à l'aide de la console, en vous plaçant dans le répertoire app_15 qui vient d'être créé et en tapant : mrt add iron-router Installez aussi bootstrap 3 comme vu dans l'activité 9. Imaginons un site composé de 3 pages HTML "Accueil", "Page 1" et "Page 2" quasiment identiques. Les 3 pages comportent un menu permettant de passer d'une page à l'autre (voir ci-dessous) L'utilisateur ayant terminé sa consultation de la page "Accueil", il désire passer à la page "Page 1", il clique donc sur le lien du menu qui lui permet d'afficher "Page 1". La page "Page 1" devra être entièrement chargée, comme si la page "Page 1" n'avait aucun point commun avec la page "Accueil" (alors que vous pouvez constater que le menu est identique pour les 2 pages). La page "Accueil" La page "Page 1" Il paraît est peu "ridicule" de charger entièrement la page "Page 1" (menu compris), l'idéal serait de charger uniquement ce qui a été modifié. C'est là qu'iron-router entre en jeu. Avec iron-router vous allez définir le "squelette" de votre page (ce qui ne changera pas), par convention, nous l’appellerons "layout". Dans le cas vu ci-dessus, le "layout" comportera uniquement le menu. À faire vous-même Dans le fichier "template.html" de l'application 15 (app_15), codez un template dénommé "layout", ce template devra afficher le menu décrit ci-dessus (pour l'instant, les attributs "src" des balises pourront rester vides). À faire vous-même Toujours dans le fichier "template.html" de l'application 15, codez un template que vous nommerez "accueil", ce template devra afficher le texte suivant : "Ceci est la page d’accueil". Faire la même chose pour le template "page1" qui affichera "Ceci est la page 2" et le template "page2" qui affichera "Ceci est la page 2". Tous les acteurs sont en places, il nous faut maintenant les relier. 23
À faire vous-même Créez un fichier "router.js" et le placez dans le dossier javascript (côté client). Saisissez le code suivant dans ce fichier : Router.configure({ layoutTemplate: 'layout' }); Router.map(function() { this.route('accueil', {path: '/'}); this.route('page1', {path: '/page1'}); this.route('page2', {path: '/page2'}); }); La première ligne "Router.configure({ layoutTemplate: 'layout' }); " permet de définir le template qui jouera le rôle de "layout" (partie qui ne sera pas modifiée quand l'utilisateur passera d'une page à l'autre). Par souci de simplicité, je vous rappelle que nous avons nommé ce template "layout" (mais vous pouvez choisir le nom qui vous conviendra). La deuxième partie du code, permet d'associer un template et une url (si cette notion d'url ne vous dit plus rien, n'hésitez pas à revoir la 1re partie de ce document) : "this.route('accueil', {path: '/'});" : permet d'associer la racine du site "/" au template que nous avons nommé "accueil". Cela signifie que l'utilisateur qui "arrivera" sur le site verra ceci (avec en local, l'adresse "localhoste:3000" dans la barre de navigation du navigateur puisque "localhoste:3000" est équivalent à ""localhoste:3000/") : "this.route('page1', {path: '/page1'}); " : si l'utilisateur clique sur "Page 1" du menu (balise Page 1) ou s'il tape directement "localhost:3000/page1" dans la barre de navigation du navigateur, il verra la page suivante s'afficher : Je pense que vous n'avez pas besoin de moi pour comprendre l'utilité de la ligne "this.route('page2', {path: '/page2'});". À faire vous-même Maintenant que vous connaissez les valeurs à attribuer aux attributs "src" (je vous avais demandé de les laisser vides dans un "À faire vous-même" ci-dessus), modifiez le fichier template.html en conséquence. Si vous testez l'application 15 maintenant, cela ne va pas fonctionner, pourquoi ? Nous n'avons pas encore spécifié "l'endroit" où devra s'afficher la partie "variable" du site (l'endroit où devra s'afficher le template correspondant à l'url). À faire vous-même Modifiez le fichier "template.html" comme suit (vous pourrez vérifier en même temps que ce que vous aviez déjà écrit est correct). 24
template.html App 15 Accueil Page 1 Page 2 {{>yield}} Ceci est la page d'accueil Ceci est la page 1 Ceci est la page 2 Vous avez sans doute remarqué le "{{>yield}} " se trouvant juste en dessous de la balise fermante nav dans le template "layout". C'est exactement à l'endroit où se trouve ce "{{>yield}} " que viendront s’insérer les différents templates définis dans le fichier "router.js". Par défaut (localhost:3000), nous aurons le template "accueil" qui prendra la place de "{{>yield}} ". Si l'utilisateur clique sur le "Page 1" du menu, le template "page1" prendra le relais du template "accueil"... Et que devient le fichier "main.html" dans tout ça ? Pas grand-chose, il est quasiment "vidé" de toute sa "substance". À faire vous-même Modifiez le fichier "main.html" puis testez l'application 15 (si cela ne fonctionne pas, reprenez les étapes une par une, si cela ne fonctionne toujours, n'hésitez pas à poser des questions) main.html App15 À faire vous-même Créez une nouvelle application (app_16). Reprenez l'application 13 (dernier "À faire vous-même" de l'activité 8) afin que le formulaire de saisi et l'affichage des fiches ne se trouvent plus sur la même page. Les fiches seront affichées sur la page d’accueil (si aucune fiche n'a été saisie, un message du type "Aucune fiche saisie" devra être affiché sur cette même page d'accueil). Un menu devra permettre à l'utilisateur de se diriger vers une page dédiée à la saisie d'une nouvelle fiche. Ce même menu devra aussi proposer à l'utilisateur de retourner à l'accueil. De plus vous utiliserez bootstrap 3 afin de proposer un formulaire un peu plus "beau" que celui proposé dans l'application 13 (n'hésitez pas à consulter la documentation). Enfin, la gestion des photos n'est pas demandée dans cette nouvelle application. Pour vous aider : • Si votre collection se nomme "Fiches", un "Fiches.find().count()" sera égal aux nombres d'entrées dans la collection. Si "Fiches.find().count()" est égal à zéro, cela signifie que votre collection "Fiches" est vide. 25
• Il est possible, dans un template, d'utiliser la structure suivante : {{#if condition}} A {{else}} B {{/if}} Si "condition" est true, le template affichera A, si "condition" est false le template affichera B 26
Vous pouvez aussi lire