Vue - Simplonline

Transcription

Vue - Simplonline
DISCOVER METEOR
Building Real-Time JavaScript Web Apps
Tom Coleman & Sacha Greif
Cover photo credit
:
,
Perseid Hunting by Darren Blackburn
Commons Attribution
.
2.0
licensed under a Creative
Generic license
.
.
www discovermeteor com
Introduction
1
.
Commençons par un petit exercice mental
ê
deux fen
é
tres diff
rentes de votre ordinateur
ê
Cliquez maintenant dans une des deux fen
'
ê
disparu de l autre fen
'
é
Il n est pas n
ê
Imaginez que vous ouvriez le m
tre
?
é
cessaire de le faire r
.
tres et effacez un fichier
--
Ce fichier a t il aussi
'
.
'
è
,
me de fichier local
'
).
Quand on
le changement s applique partout
(
sans avoir besoin de rafra chir ou d utiliser une fonction de rappel
.
.
ellement pour savoir que c est bien le cas
modifie quelque chose dans notre syst
î
me dossier dans
callback
Ça marche
,
tout
simplement
Par contre
,
ê
imaginons ce m
ouvriez le m
que vous cr
ê
et m
ê
'
é
me sc
.
nario sur le web
é
Consid
rons par exemple que vous
ê
me panneau d administration Wordpress dans deux fen
é
'
'
.
iez un nouveau post dans l une d elles
'
,
me si vous attendez
é
Nous nous sommes habitu
,
que par de courtes actions
,
Heureusement
ê
l autre fen
'
s d ann
'
,
tres de navigateur
é
Contrairement à l exp
rience pr
î
é
c
,
dente
.
tre ne changera pas à moins de la rafra chir
é
é
es en ann
'
é
es à l id
'
e qu on ne communique avec un site
.
distinctes les unes des autres
'
Meteor fait partie d une nouvelle vague de frameworks et de technologies qui
-é ( -
comptent bien remettre en question ce statu quo en rendant le web temps r
r
éé
puis
.
el
)
real time
et
actif
Qu'est-ce que Meteor ?
-
é
Meteor est une plate forme bas
'
.
é
e sur Node js pour cr
é
C est ce qui fait le lien entre la base de donn
,
utilisateur
é .
er des applications web temps r
es de votre application et son interface
é.
tout en assurant que les deux restent bien synchronis
é
Puisque Meteor est bas
Autre chose
el
,
. ,
sur Node js
s
ôé
il utilise JavaScript à la fois c
t
ôé
client et c
t
.
serveur
Meteor permet aussi de partager du code entre les deux environnements
.
-
ê
Tout cela nous donne une plate forme pouvant
'
tre tr
è
s puissante et tr
fournissant une couche d abstraction à de nombreux probl
'
é
d
è
è
mes et pi
è
s simple en
ges rencontr
é
s lors du
.
veloppement d applications web
Pourquoi Meteor ?
'
ô
Bon alors pourquoi passer votre temps à apprendre Meteor plut
é
Sans compter les nombreuses fonctionnalit
à apprendre
é
Compar
'
?
la raison est claire
:
Meteor est facile
.
-
,
aux autres plate formes
application web temps r
é
d exp
,
s de Meteor
-
t qu une autre plate forme
rience avec le d
'
é
'
'
Meteor permet l impl
é
-
,
veloppement front end
-ê
'
.
-
é
tre la plate forme id
'
Puisqu il ne faut qu une soir
ale qui r
-
é
ê
vous
é
'
é
mentation et le d
el en l espace de seulement quelques heures
vous n aurez pas à apprendre un nouveau langage
Meteor est peut
é
ploiement d une
Et si vous avez un peu
é
tes d
jà familier avec le JavaScript et
.
,
pond à tous vos besoins
é
e ou un week end pour d
,
marrer
-ê
mais peut
.
tre pas
pourquoi ne pas essayer
?
Pourquoi ce livre ?
è
Sur les deux derni
res ann
é ,
es
é
nous avons travaill
avons fait des applications webs et mobiles
,
Nous avons beaucoup appris
è
tr
.
open source et commerciales
é
mais trouver les r
è
s simple
,
Il nous a fallu assembler les pi
.
me inventer nos propres solutions
é
ces leçons et cr
'
er un guide simple et d
construction d une application Meteor
é
taill
é
,
Avec ce livre
.
nouvelles tels que Hacker News ou Reddit
,
construirons
re
,
et
qui vous aiderait à travers toutes les
é
tapes de la
.
'
è ,
tait pas toujours
nous souhaitions partager toutes
é
L application que nous allons construire est une version simplifi
avec son grand fr
Nous
.
'é
ponses à nos questions n
.
ces du puzzle à partir de sources multiples
ê
souvent m
sur de nombreux projets Meteor
'
Nous l avons appel
é
e des sites sociaux de
Microscope
).
Telescope un autre projet Meteor open source
nous vous apprendrons tout les
éé
l
é
ments n
,
application Meteor comme la gestion des utilisateurs
(
par analogie
Pendant que nous le
é
cessaires au d
'
veloppement d une
,
les collections Meteor
le routing et
.
beaucoup plus
À qui ce livre est-il destiné ?
Un de nos objectifs en
vous devriez
é
tre capable de suivre le cours sans exp
,
,
.
JavaScript
.
crivant ce livre est de garder les choses simples et accessibles
ê
frameworks MVC
En revanche
é
ôé
ou encore de la programmation c
é
Mais si vous avez d
,
veloppeur du navigateur
jà exp
t
é
alable de Meteor
. ,
Node js
des
é é .
serveur en g
n
l
ral
mentaire de la syntaxe et des concepts du
é
é
é
riment
un peu de code jQuery ou jou
è
vous ne devriez pas avoir de probl
me
œ
il à JavaScript primer for Meteor
(
)
en anglais
avec la console
.
,
Si vous ne vous sentez pas au point avec JavaScript pour le moment
jeter un
,
éé
on attend un connaissance
é
d
rience pr
,
Ainsi
é
nous vous sugg
avant de revenir sur ce livre
rons de
.
À propos des auteurs
ù
Au cas o
vous vous demandez qui nous sommes et pourquoi vous pouvez nous faire
confiance
,
'
.
voici un peu d information sur nous
,
é
Tom Coleman fait partie de Percolate Studio
é
qualit
'
é
et l exp
.
rience utilisateur
pour vos applications Meteor
(
Meteor open source
.
Enfin
,
'
,
galement sur Atmosphere
'
è
c est aussi l un des cerveaux derri
).
é
un service de paquet
re de nombreux projets
avec des startups comme Hipmunk et RubyMotion en tant que
.
concepteur produit et concepteur web
),
veloppement web ciblant la
par exemple Iron Router
Sacha Greif a travaill
Telescope
é
Il travaille
un studio de d
Il est le cr
é
ateur de Telescope et de Sidebar
.
(
é
bas
sur
et il est aussi le fondateur de Folyo
Chapitres & Apartés
’
Nous voulions que ce livre soit utile aussi bien pour l utilisateur novice de Meteor que pour le
é,
programmeur avanc
normaux
(
é
num
rot
é
é
ainsi nous avons s
s de
1 14
à
)
par
é
et les apart
s
é
(
é
les chapitres en deux cat
num
é
ros
)
.5 .
gories
:
les chapitres
’
,
Les chapitres normaux constituent la ligne conductrice pour construire l application
essayerons de la rendre op
é
è
rationnelle d
s que possible en expliquant les
é
importantes sans vous encombrer de d
’
D un autre c
ô é,
les apart
,
Ainsi
si vous
.
é
s iront plus loin dans les subtilit
mieux comprendre ce qui se passe r
ê
é
tes d
,
butant
tapes les plus
tails
é
t
é
et nous
s de Meteor
é
,
et vous aideront à
.
ellement dans les coulisses
é
vous pouvez passer les apart
revenir à elles une fois que vous aurez jou
é
è
s pour votre premi
un peu avec Meteor
re lecture
,
et
.
Commits & Instances en ligne
’
Il n y a rien de pire que de suivre un livre de programmation et de tout à coup se rendre
’
é
compte que le code n est plus synchronis
é .
comme pr
Pour
é
avec les exemples et que plus rien ne fonctionne
vu
,
viter cela
éé
nous avons cr
é ô
un d
p
,
t sur GitHub pour Microscope
é
et nous proposerons
galement des liens directs vers les commits de Git à chaque modification de code
chaque commit est li
é
’
,
à une instance en ligne de l application
.
avec votre copie locale
'
’
Lancer l instance
ce n est pas parce que nous mettons à votre disposition ces commits que
’
.
vous devez juste passer d un checkout au suivant
é
temps n
te
'
Voir sur GitHub
,
:
ê .
Afficher les notifications dans l ent
Une seule chose
,
De plus
ainsi vous pourrez le comparer
Ici un exemple de ce que vous pourriez voir
Commit 11-2
.
cessaire pour
é
’
Vous apprendrez mieux si vous prenez le
crire le code de l application
Quelques ressources supplémentaires
!
Si jamais vous souhaitez en apprendre plus sur un point pr
é
cis de Meteor
officielle de Meteor est le meilleur endroit pour commencer
Nous vous recommandons
,
questions
é
#
la documentation
.
galement Stack Overflow pour la r
ainsi que le canal IRC
,
’
é
solution de probl
è
mes et les
.
meteor si vous avez besoin d aide en direct
Ai-je besoin de Git ?
'
é
Il n est pas n
,
livre
cessaire d
'ê
é
tre familiaris
avec le contr
ô
le de versions Git pour suivre ce
.
mais nous le recommandons fortement
é
.
Si vous souhaitez passer à la vitesse sup
rieure
,
nous vous recommandons Git Is
Simpler Than You Think de Nick Farina
Si vous
(
ê
tes un d
)
Mac OS
é
butant
,
nous vous recommandons
é
qui vous permet de g
(
SourceTree
Mac OS
&
é ô
rer vos d
),
Windows
p
é
’
galement l application GitHub
ts sans utiliser la ligne de commande
tous deux gratuits
,
ou
.
Nous contacter
,
Si vous souhaitez nous contacter
@
hello
ê
De m
.
vous pouvez nous envoyer un email à
.
discovermeteor com
me
,
si vous trouvez une erreur typographique ou toute autre erreur dans le
,
contenu du livre
é ô
vous pouvez nous en informer en soumettant un bug dans ce d
p
t
.
GitHub
è
Si vous avez un quelconque probl
soumettre un bug dans le d
,
Enfin
é ô
p
me avec le code de Microscope
,
vous pouvez
.
t de Microscope
pour toute autre question vous pouvez aussi nous laisser un commentaire dans le
panneau lat
é
.
ral de cette application
Premiers pas
è
La premi
2
,
re impression est importante
'
é.
l installation de Meteor devrait se faire sans difficult
.
Vous serez en selle en moins de cinq minutes dans la plupart des cas
Pour commencer
,
si vous
terminal et en saisissant
ê
tes sur Mac OS ou Linux vous pouvez installer Meteor en ouvrant un
:
curl https://install.meteor.com | sh
Si vous
ê
r
'
Ne pas
é
diatement
'
.
é
cutable
meteor
è
sur votre syst
è
,
me
—
ou ne souhaitez pas
—
.
,
,
et vous permettra de
installer Meteor localement sur votre
'
.
.
nous vous invitons à examiner Nitrous io en guise d alternative
'
é
Nitrous io est un service qui vous permet d ex
code
me
installer Meteor
Si vous ne pouvez pas
syst
.
rez vous aux instructions d installation du site de Meteor
f
Cette commande installera l ex
l utiliser imm
'
-
, éé
tes sur Windows
directement dans votre navigateur
œ
vous aider à le mettre en
.
Nous avons r
,
é
é
dig
'é
et d
diter leur
un petit guide pour
.
uvre
'
Suivez simplement ce guide jusqu à la section
revenez dans ce chapitre
,
cuter vos applications
à la section
«
Cr
é
“
Installing Meteor
”
,
comprise
er une application basique
».
puis
Créer une application basique
Maintenant que Meteor est install
ligne de commande
meteor :
é, é
cr
.
ons une application
,
Pour ce faire
'
on utilise l outil en
meteor create microscope
Cette commande t
'
.
l emploi
'
éé
l
,
chargera Meteor
,
Lorsqu elle aura abouti
contenu suivant
puis
é
tablira un projet Meteor
vous devriez trouver un dossier
éé
l
mentaire
microscope/
, ê
pr
t à
avec le
:
.meteor
microscope.css
microscope.html
microscope.js
'
éé
L application que Meteor a cr
é
cependant d
œ
uvre quelques patterns courants
ê
M
'
jà en
e pour vous est une simple
me si notre application ne fait pas grand chose
,
l application
,
é
(
bauche
),
.
boilerplate
é
nous pouvons d
retournez à la ligne de commande et saisissez
é
jà la d
qui met
marrer
.
Pour lancer
:
cd microscope
meteor
ê
Ouvrez une fen
'
tre de navigateur à l adresse
http://localhost:3000/
)
http://0.0.0.0:3000/ , ce qui est équivalent
ressemble à
:
(
'
ou à l adresse
et vous devriez voir quelque chose qui
Le ‹ Hello World › de Meteor.
Commit 2-1
é
Cr
e un projet Microscope
Voir sur GitHub
é
F
licitations
ê
arr
'
!
.
mentaire
'
è
,
ter l application
'
.
re application Meteor
,
Au passage
pour
ê
il vous suffit de ramener au premier plan la fen
,
tre de terminal dans
et de presser la combinaison de touches
,
N oubliez pas que si vous utilisez Git
init .
l
Lancer l instance
Vous avez mis en service votre premi
laquelle tourne l application
'
éé
'
ctrl+c .
c est le bon moment pour initialiser votre repo avec
git
Bye Bye Meteorite
ù
0.9.0
Il fut un temps o
Meteor
Depuis la version
é é
int
gr
é
tait reli
de Meteor
,
.
é
à un gestionnaire de paquet nomm
'
é
Meteorite n est plus n
é
Meteorite
'
.
éé
cessaire puisqu il a
t
directement dans Meteor
Donc si vous voyez une r
éé
f
rence à la ligne de commande
travers de ce livre ou sur Internet
,
mrt
de Meteorite au
vous pouvez simplement la remplacer par
meteor .
Ajouter un paquet
Nous allons maintenant utiliser le syst
è
me de paquet de Meteor pour ajouter Bootstrap à
.
notre projet
'
é
Il n y a aucune diff
é
rence par rapport à la m
' --
'
thode usuelle c est à dire l inclusion manuelle
des fichiers CSS et JavaScript de Bootstrap à part le fait que nous laissons le soin au
mainteneur du paquet de le garder à jour
'
Pendant qu on y est
,
.
nous allons aussi installer Underscore
Underscore est une biblioth
è
utilitaire pour JavaScript vraiment tr
Le paquet
.
bootstrap
que
é .
s pratique pour manipuler des donn
'
est maintenu par l utilisateur
, twbs:bootstrap .
è
es
twbs , ce qui nous donne son nom
complet
En revanche
,
le paquet
underscore
,
fournis par le framework
'
fait partie des paquets
c est pourquoi il ne poss
è
«
'
officiel
de pas d auteur
»
de Meteor qui sont
:
meteor add twbs:bootstrap
meteor add underscore
Notez que nous ajoutons Bootstrap
3.
'é
Certaines captures d
cran de ce livre ont
avec une ancienne version de Microscope utilisant Bootstrap
2,
éé
'
t
prises
ce qui signifie qu elles seront
l
é è
g
rement diff
é
rentes de votre version
.
Commit 2-2
Avec les paquets Bootstrap et Underscore
.
'
Voir sur GitHub
Lancer l instance
'
è
Vous devriez voir d
de Bootstrap
s maintenant quelques changements dans votre application suite à l ajout
:
Avec Bootstrap.
Contrairement à la
“
”
traditionnelle
'
è
mani
,
re d inclure des ressources externes
'
lier aucun fichier CSS ou JavaScript car Meteor s en occupe pour nous
'
!
.
avantage des paquets Meteor parmi tant d autres
'
nous n avons à
'
'
Mais ce n est qu un
À propos des paquets
Lorsque nous parlons de paquets
'ê
d
é .
tre pr
cis
Le c
œ
(
)
packages
,
dans le contexte de Meteor
:
Meteor distingue cinq types de paquets
-
ur de Meteor comprend lui m
).
ê
é
me diff
rents paquets essentiels
Ils font partie de chaque application Meteor
packages
,
'
Les paquets classique de Meteor se nomment
isomorphes
).
(
'
“
.
”,
isopacks
-
accounts-ui
maintenus par la team Meteor et sont directement
]
//
:
.
é
é
velopp
(
'
.
é
).
'
appcache
ou
é é
int
gr
s à
é
s sur le serveur de
Vous pouvez les trouver sur Atmosphere ou avec la
(
)
é
sont des paquets sp
local packages
-
(
,
NPM packages
cifiques que vous
/packages .
.
Node js Packaged Modules
)
sont des paquets
,
Bien qu ils ne fonctionneront pas tels quels avec Meteor
tre exploit
é
sont
sont simplement des isopacks
er et placer dans le sous dossier
Les paquets NPM
ê
)
Third party packages
Les paquets locaux
. .
ou paquets
packages
meteor search .
commande
Node js
-
/#
[
s par d autres utilisateurs qui les ont envoy
paquet de Meteor
pouvez cr
.
docs meteor com
Les paquets tiers
d
core
ce qui signifie qu ils peuvent fonctionner sur le client et sur le
First party packages comme
Meteor http
(
et vous n aurez
pratiquement jamais besoin de vous en soucier
serveur
il est bon
s par les pr
éé
c
ils peuvent
.
dents types de paquets
La structure de fichiers d'une application Meteor
,
Avant de plonger dans le code
'
l assemblage
en les fichiers
Puis cr
)
build
ez
,
ouvrez le dossier
microscope.html , microscope.js
ez quatre dossiers dans
cr
'
ne contienne que l essentiel
é
, é
Enfin
(
.
il convient de configurer notre projet correctement
main.html
et
main.js
/client . Ne vous inquiétez pas si votre
,
.
microscope.css .
dans
-
et supprimez
/microscope : /client , /server , /public , et /lib .
application ne fonctionne plus pour le moment
chapitres suivants
et
microscope
Afin que
nous allons remplir ces fichiers dans les
-
.
Certains de ces sous dossiers sont particuliers
conventions suivantes
:
n est ex
Le code dans le dossier
/client
n est ex
é
galement tr
é
cut
é
.
.
que par le client
.
(
,
,
polices
images
)
etc
vont dans le dossier
/public .
î
/lib
é
sont charg
sont charg
é
.
s avant tous les autres
.
è
s apr
s les autres
'
é
dans l ordre alphab
.
tique
Meteor ne vous contraint pas à utiliser de structure pr
éé
La structure sugg
r
-
é
e et d
:
é
main.*
Tout le reste est charg
,
é
cut
que par le serveur
s utile de conna tre dans quel ordre Meteor charge vos fichiers
Tous fichiers
Au reste
é
é
cut
à la fois par le client et le serveur
è
Les fichiers dans
.
é
/server
Vos ressources statiques
pas
'
'
Le code dans le dossier
Tout le reste est ex
Il est
Meteor traite les fichiers des dossiers selon les
é é
d
finie
,
si vous ne le souhaitez
é
crite ci dessus correspond à notre façon de proc
.
,
der
'
elle n est
en aucun cas inamovible
Nous vous encourageons à consulter la documentation officielle de Meteor si vous souhaitez
é
davantage de d
tails à ce sujet
.
Meteor est-il MVC ?
é
Si vous avez utilis
'
,
d autres frameworks
demander si Meteor suit le pattern MVC
,
Pour faire court
non
.
À la diff
é
d
.
finie à votre application
,
la façon qui fait sens pour nous
Public ou pas ?
)
Model View Controller
rence de Rails
é é
fichiers pr
(
,
.
tels que Ruby on Rails
,
vous pourriez vous
'
Meteor n impose aucune structure de
Dans ce livre
,
nous disposerons notre code de
sans trop nous soucier des acronymes
.
è
Pardonnez notre exc
'
è .
s de z
le
En pratique
'
,
car Microscope n utilisera pas de ressources statiques
'
é
signaler l utilit
,
de ce dossier
/public ,
nous n aurons pas besoin du dossier
!
é
N
anmoins
,
nous avons voulu vous
car la plupart des applications Meteor comprendront tout au
.
moins quelques images
,
À ce propos
' '
vous avez peut
ù
C est l emplacement o
-ê
tre observ
é
é
la pr
é
—
ê
ter attention à son contenu
.meteor/packages
et
paquets intelligents
(
é
,
Meteor enregistre son propre code
peut conduire à un effet potentiellement d
de pr
'
sence d un dossier cach
,
sinon
.
sastreux
nomm
é .meteor .
et y apporter des modifications
'
é é
Vous n aurez g
,
à de rares exceptions
n
ralement pas besoin
aux fichiers
.meteor/release , qui contiennent respectivement la liste de vos
)
.
et la version de Meteor en usage dans votre projet
smart packages
,
Lorsque vous ajoutez des paquets et changez de version de Meteor
changements en examinant ces deux fichiers
é
vous pouvez v
rifier ces
.
Tirets_bas vs CasseAlternée
'
(
(
'
é
À l antique d
caract
è
bat concernant l usage
,
re underscore
CamelCase
,
,
'
,
)
—
è
apr
'
é camelCase ,
,
,
s tout
on
é
crit JavaScript
è
,
et les classes CSS
e
,
gle
é
'
-
ê
dans la syntaxe CSS elle m
me
'
parce que c est
et non java
qui utilisent des tirets
(
.
matiquement
_
script
!
qui utilisent des tirets bas
è
( .ma-classe ).
,
font-family , text-align ,
en est que les tirets bas sont habituels dans les syst
utilis
de tirets bas
é
pourvu que vous l appliquiez syst
Les noms de fichiers font exception à cette r
( mon_fichier.js ),
)
'
nous utilisons la casse altern
l usage avec JavaScript
,
maVariable , nous n ajouterons rien, sinon qu importe la
convention que vous adopterez
Dans cet ouvrage
'
dans les noms d identifiants
ma_variable , ou de la casse alternée
comme dans
comme dans
,
mes de fichiers
La raison
et que le tiret est
)
.
etc
CSS sans coquetterie
.
Ce livre ne traite pas de CSS
ééé
nous avons pr
'
, è
n aurez
d
f
r
,
s lors
Ainsi
,
é
pour ne pas vous ralentir avec des consid
è
vous mettre à disposition la feuille de style compl
plus à vous en pr
é
occuper
.
è
te d
,
rations de style
é
s le d
.
part
Vous
é
Les feuilles de style CSS sont automatiquement charg
'
de sorte qu elles doivent
ê
é
tre plac
.
-
/client/stylesheets/ , puis placez
-,
Allez y
y un fichier
cr
é
es à la vol
é
é
-
-
,
e par Meteor
/client , plutôt que /public
es dans le dossier
le seraient les autres ressources statiques
es et comprim
comme
ez y maintenant un sous dossier
style.css
avec le contenu suivant
:
.grid-block, .main, .post, .comments li, .comment-form {
background: #fff;
border-radius: 3px;
padding: 10px;
margin-bottom: 10px;
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);
-moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); }
body {
background: #eee;
color: #666666; }
#main {
position: relative;
}
.page {
position: absolute;
top: 0px;
width: 100%;
}
.navbar {
margin-bottom: 10px; }
/* line 32, ../sass/style.scss */
.navbar .navbar-inner {
border-radius: 0px 0px 3px 3px; }
#spinner {
height: 300px; }
.post {
/* For modern browsers */
/* For IE 6/7 (trigger hasLayout) */
*zoom: 1;
position: relative;
opacity: 1; }
.post:before, .post:after {
content: "";
display: table; }
.post:after {
clear: both; }
.post.invisible {
opacity: 0; }
.post.instant {
-webkit-transition: none;
-moz-transition: none;
-o-transition: none;
transition: none; }
.post.animate{
-webkit-transition: all 300ms 0ms;
-moz-transition: all 300ms 0ms ease-in;
-o-transition: all 300ms 0ms ease-in;
transition: all 300ms 0ms ease-in; }
.post .upvote {
display: block;
margin: 7px 12px 0 0;
float: left; }
.post .post-content {
float: left; }
.post .post-content h3 {
margin: 0;
line-height: 1.4;
font-size: 18px; }
.post .post-content h3 a {
display: inline-block;
margin-right: 5px; }
.post .post-content h3 span {
font-weight: normal;
font-size: 14px;
display: inline-block;
color: #aaaaaa; }
.post .post-content p {
margin: 0; }
.post .discuss {
display: block;
float: right;
margin-top: 7px; }
.comments {
list-style-type: none;
margin: 0; }
.comments li h4 {
font-size: 16px;
margin: 0; }
.comments li h4 .date {
font-size: 12px;
font-weight: normal; }
.comments li h4 a {
font-size: 12px; }
.comments li p:last-child {
margin-bottom: 0; }
.dropdown-menu span {
display: block;
padding: 3px 20px;
clear: both;
line-height: 20px;
color: #bbb;
white-space: nowrap; }
.load-more {
display: block;
border-radius: 3px;
background: rgba(0, 0, 0, 0.05);
text-align: center;
height: 60px;
line-height: 60px;
margin-bottom: 10px; }
.load-more:hover {
text-decoration: none;
background: rgba(0, 0, 0, 0.1); }
.posts .spinner-container{
position: relative;
height: 100px;
}
.jumbotron{
text-align: center;
}
.jumbotron h2{
font-size: 60px;
font-weight: 100;
}
@-webkit-keyframes fadeOut {
0% {opacity: 0;}
10% {opacity: 1;}
90% {opacity: 1;}
100% {opacity: 0;}
}
@keyframes fadeOut {
0% {opacity: 0;}
10% {opacity: 1;}
90% {opacity: 1;}
100% {opacity: 0;}
}
.errors{
position: fixed;
z-index: 10000;
padding: 10px;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
pointer-events: none;
}
.alert {
animation: fadeOut 2700ms ease-in 0s 1 forwards;
}
-webkit-animation: fadeOut 2700ms ease-in 0s 1 forwards;
-moz-animation: fadeOut 2700ms ease-in 0s 1 forwards;
width: 250px;
float: right;
clear: both;
margin-bottom: 5px;
pointer-events: auto;
/
/
.
client stylesheets style css
Commit 2-3
Structure de fichiers r
Voir sur GitHub
é
é .
organis
e
'
Lancer l instance
Au sujet de CoffeeScript
,
Dans ce livre
nous
é
,
utiliser CoffeeScript
CoffeeScript et vous
.
crirons les scripts en JavaScript pur
'
Meteor n est pas en reste
ê
é:
tes par
meteor add coffeescript
.
éé
Si vous pr
f
é
rez n
anmoins
Ajoutez simplement le paquet
Déploiement
2.5
SIDEBAR
'
'
,
Certaines personnes aiment travailler tranquillement sur un projet jusqu à ce qu il soit parfait
'
ô
tandis que d autres ne peuvent pas attendre de le montrer au monde le plus t
Si vous
'
ê
l instant
,
vous
ê
tes libre de sauter ce chapitre
de temps pour apprendre comment d
'
qu il vous faut
é
.
'
'
é
ô é
rez plut
ô é,
D un autre c
t
t d
velopper en local pour
si vous voulez prendre un peu
ployer votre application Meteor en ligne
é
,
nous avons ce
'
.
ployer une application Meteor de plusieurs façons
'
tes libres d utiliser chacune d elles à n importe quelle
d
f
.
Nous allons apprendre comment d
ê
éé
tes le premier type de personne et que vous pr
.
t possible
é
Vous
tape de votre processus de
veloppement si vous travaillez sur Microscope ou une autre application Meteor
.
-!
Allons y
Présentation des Sidebars
Ceci est un chapitre sidebar
(
apart
,
sur des sujets concernant Meteor
Donc si vous pr
éé
è
f
sauter sans probl
rez plut
)
é,
les Sidebars donnent une vision approfondie
é
ind
.
pendamment du reste du livre
ô
t continuer à travailler sur Microscope
,
vous pouvez le
.
me maintenant et y revenir plus tard
Déployer sur Meteor
é
D
-
ployer sur un sous domaine Meteor
simple et la premi
è
i e
.
re que nous testerons
,
dans ses premiers jours
D
( . . http://myapp.meteor.com )
Ça peut
ê
é
tre utile pour pr
'
est l option la plus
senter votre application
.
ou de mettre en place rapidement un serveur de test
é
.
ployer sur Meteor est simple
application Meteor et tapez
:
Ouvrez juste votre terminal allez dans le r
é
pertoire de votre
meteor deploy myapp.meteor.com
û,
Bien s
éé
pr
f
r
vous devrez faire attention à remplacer
'
é
rence un qui n est pas d
'
é.
.
Meteor
'
è
'
éé
f
é
il vous sera demand
de cr
'
é
de
er un compte
é
s quelques secondes vous serez capable d acc
der à votre
'
rer à la documentation officielle pour plus d informations sur des
é
choses comme acc
,
avec un nom de votre choix
http://myapp.meteor.com .
application à l adresse
Vous pouvez vous r
,
ploiement d application
Et si tout va bien apr
”
myapp
jà utilis
é
Si c est votre premier d
“
é
der directement à la base de donn
é
configurer un domaine personnalis
é
es de votre instance h
é
berg
e ou
.
pour votre application
Déployer sur Modulus
é
Modulus est une bonne option pour d
fournisseurs PaaS
(
- --
)
platform as a service
é
quelques personnes qui ex
. .
ployer des applications Node js
'
C est un des
qui supporte officiellement Meteor
,
é
et il y a d
jà
.
cutent des applications Meteor en production dessus
é
Vous pouvez en apprendre plus à propos de Modulus en lisant leur guide de d
ploiement
.
pour application Meteor
Meteor Up
,
Bien que de nouvelles solutions de cloud apparaissent chaque jour
è
avec leurs lots de probl
mes et de limitations
.
’
, é
Donc aujourd hui
d
elles viennent toujours
ployer sur votre propre
.
serveur reste le meilleur moyen de mettre votre application Meteor en production
é
chose est que d
-
é
d
'
ê
ployer vous m
me n est pas si simple
ploiement en production de qualit
Meteor Up
(
ou
mup
surtout si vous recherchez un
é.
de son petit nom
'
,
)
è
est une autre tentative de solution à ce probl
é
un outil en ligne de commande qui s occupe de la configuration et du d
é
Regardons comment d
La seule
.
ployer Microscope en utilisant Meteor Up
me
,
avec
.
ploiement pour vous
,
Avant tout autre chose
$
é
qui d
5
marre à
,
par mois
è
rapidement des probl
Up devrait
ê
'
nous aurons besoin d un serveur
,
ou AWS
é,
).
,
un login
(
habituellement
ô
nous en aurons bient
t besoin
!
root
(
vous aurez
mais si vous cherchez juste un terrain de jeu Meteor
Quel que soit le service que vous choisissez
serveur
,
Nous recommandons Digital Ocean
qui fournit des Micro instances gratuitement
mes de scalabilit
tre suffisant
.
,
ou
vous obtiendrez trois choses
)
:
'
l adresse IP de votre
-
ubuntu , et un mot de passe. Gardez
ô é,
les de c
t
Initialiser Meteor Up
é
Pour d
,
marrer
'
nous aurons besoin d installer Meteor Up via
npm
comme suit
:
npm install -g mup
é
Nous allons cr
er ensuite un r
Meteor Up pour un d
raisons
:
'
é
é
é
pertoire s
par
ploiement particulier
c est mieux d
'é
'
.
é,
é
sp
cial qui contiendra vos configurations
é
Nous utilisons un r
é
viter d inclure des donn
es priv
é
é
pertoire s
par
é ô
es dans votre d
p
é
pour deux
,
t Git
é
sp
cialement
.
si vous travaillez sur du code public
è
Deuxi
,
mement
é
en utilisant plusieurs r
pertoires s
è .
plusieurs configurations Meteor Up en parall
le
é
é,
par
s
Ça sera tr
é
nous serons capables de g
è
rer
é
s pratique pour d
ployer des
.
instances de production et de tests par exemple
é
Cr
ons ce nouveau r
é
pertoire et utilisons le pour initialiser un nouveau projet Meteor Up
mkdir ~/microscope-deploy
cd ~/microscope-deploy
mup init
:
Partage avec Dropbox
'
Un bon moyen de s assurer que vous et votre
é
de d
é
.
ploiement est simplement de cr
votre Dropbox
,
é
ê
quipe utilise les m
mes configurations
er un dossier de configuration Meteor Up dans
ou un service similaire
Configuration Meteor Up
Quand on initialise un nouveau projet
,
Meteor Up va cr
er deux fichiers pour vous
: mup.json
settings.json .
et
mup.json
é
gardera toutes vos configurations relatives au d
settings.json
,
jetons analytics
'é
L
é
é éé
faut g
n
r
,
ploiement
'
pendant que
contiendra toutes les configurations relatives à l application
)
..
etc
tape suivante est de configurer votre fichier
d
é
par
(
,
jetons OAuth
mup.json . Voici le fichier mup.json
par
mup init , et tout ce que vous avez à faire est de remplir les blancs :
{
//info d'authentication serveur
"servers": [{
"host": "hostname",
"username": "root",
"password": "password"
//ou fichier pem (authentification basée sur ssh)
//"pem": "~/.ssh/id_rsa"
}],
//installer MongoDB sur le serveur
"setupMongo": true,
//chemin de l'application (répertoire local)
"app": "/path/to/the/app",
}
//configuration environnementale
"env": {
"ROOT_URL": "http://supersite.com"
}
.
mup json
.
Traversons chacune de ces configurations
Server Authentication
'
é
Vous noterez que Meteor Up supporte l authentification par cl
mots de passe
( ),
PEM
Note importante
'
:
donc il peut
ê
é
tre utilis
'
s priv
é
é
es et bas
es sur des
.
avec la plupart des fournisseur de cloud
'
Si vous choisissez d utiliser l authentification par mot de passe
é sshpass
vous d avoir install
é
au pr
alable
(éé r
f
).
,
-
assurez
rez vous à ce guide
Configuration MongoDB
L
'é
é
tape suivante est de configurer une base de donn
'
'
.
es MongoDB pour votre application
Nous vous recommandons d utiliser Compose ou n importe quel autre fournisseur de cloud
.
MongoDB car ils offrent un support professionnel et de meilleurs outils de gestion
é
Si vous avez d
'
'
é
cid
,
d utiliser Compose
MONGO_URL
d environnement
,
MongoDB avec Meteor Up
dans le bloc
mettez juste
setupMongo
mettez
env
à
false
et ajoutez la variable
'
mup.Json . Si vous décidez d héberger
de
setupMongo
true
à
'
et Meteor Up s occupera du
.
reste
'
Chemin de l application Meteor
é
Maintenant que notre configuration Meteor Up a pris vie dans un r
é
pertoire diff
,
rent
nous
éé
allons avoir besoin de faire pointer Meteor Up vers notre application en utilisant la propri
t
app . Entrez juste votre chemin local complet, que vous pouvez trouver en utilisant la
pwd
commande
dans le terminal quand vous
ê
é
tes plac
dans votre r
é
pertoire
.
'
Variables d environnement
é
Vous pouvez sp
'
cifier toutes les variables d environnement de votre application
) '
ROOT_URL , MAIL_URL , MONGO_URL , etc.
é
à l int
rieur du bloc
env .
(
telles que
Configurer et déployer
'
é
Avant qu on puisse d
é
h
'
ployer nous allons avoir besoin de configurer le serveur pour qu il puisse
berger des applications Meteor
dans une seule commande
!
.
La magie de Meteor Up encapsule ce processus complexe
mup setup
Ça va prendre quelques minutes en fonction de la performance du serveur et de la
é é
connectivit
r
.
seau
application avec
:
Apr
è
è
s le succ
'
,
s de l installation
é
vous pouvez finalement d
ployer votre
mup deploy
Ça va compacter votre application Meteor
,
é
et la d
ployer sur le serveur que nous venons de
.
mettre en place
Afficher les journaux
Les journaux sont importants et Meteor Up fournit un moyen tr
é
mulant la commande
è
s facile de les manipuler en
tail -f . Tapez juste :
mup logs -f
'
é
Ça vous donne une vue d ensemble des capacit
é
rons de visiter le d
nous vous sugg
é
Ces trois façons de d
.
des cas
û,
Bien s
r
.
s de Meteor Up
é ô
p
…
-ê
ou peut
.
ployer des applications Meteor devrait
'
nous savons que plusieurs d entre vous pr
tre un autre livre
!
,
t Github de Meteor Up
.
complet et configurer leur serveur Meteor de bout en bout
jour
'
Pour plus d informations
ê
tre suffisantes pour la plupart
éé
f
ô
reront avoir un contr
'
le
Mais c est un sujet pour un autre
Templates
3
é
Pour faciliter le d
'
é
vers l int
.
rieur
,
veloppement dans Meteor
'
,
En d autres termes
é
nous la rattacherons à la m
'
nous allons adopter une approche de l ext
nous allons cr
'
é
/
,
er une simple page html javascript
.
é
rieur
puis
canique interne de l application plus tard
'
Ce qui veut dire que dans ce chapitre nous nous occuperons de ce qu il se passe dans le
é
r
pertoire
/client .
'
é
Si vous ne l avez pas d
é
r
pertoire
/client
jà fait
é
et ins
, é
cr
ez un nouveau fichier appel
rez le code suivant
é main.html
dans votre
:
<head>
<title>Microscope</title>
</head>
<body>
<div class="container">
<header class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="/">Microscope</a>
</div>
</header>
<div id="main">
{{> postsList}}
</div>
</div>
</body>
/
.
client main html
.
Ce sera le template principal de notre application
HTML except
'
é
'
pour la balise d inclusion de template
d insertion pour le template
é
cr
é
er deux templates suppl
Les templates Meteor
postsList
.
mentaires
'
Comme vous pouvez le voir c est du langage
{{> postsList}} , qui est un point
ô.
que nous verrons bient
t
Nous allons maintenant
En son c
'
œ ,
ur
é
un site d actualit
é
s social est compos
'
é
d articles organis
,
s en listes
'
et c est
.
exactement de cette façon que nous allons organiser nos templates
é
Cr
é
ons un r
,
templates
/templates
pertoire
dans
'
/client . C est ici que nous mettrons tous nos
et pour garder les choses en ordre nous allons
/templates
é
é
galement cr
juste pour nos templates relatifs aux articles
(
).
er
/posts
dans
posts
Recherche de fichiers
é
Meteor est g
.
nial pour trouver les fichiers
é
dans le r
pertoire
'
Ça signifie
ê
m
me r
(
'
'é
include
)
crire manuellement des chemins
.
pour les fichiers javascript ou CSS
é
galement que vous pourriez aussi bien mettre tous vos fichiers dans le
é
,
pertoire
ou m
ê
ê
me tout votre code dans le m
é
Meteor compilera tout dans un seul fichier minifi
ô
plut
vous mettez votre code
/client , Meteor le trouvera et le compilera proprement. Ce qui
signifie que vous n avez jamais besoin d
d inclusion
ù
Peu importe o
é
t les choses bien organis
me fichier
.
,
de toute façon
Mais sachant que
nous garderons
es et utiliserons une structure de fichier la plus claire
.
possible
ê
Nous sommes finalement pr
é
t pour cr
er notre second template
client/templates/posts , créez posts_list.html :
<template name="postsList">
<div class="posts">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
/
/
/
_
client templates posts posts
Et
post_item.html :
.
list html
.
Dans
<template name="postItem">
<div class="post">
<div class="post-content">
<h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
</div>
</div>
</template>
/
/
/ _
'
name="postsList"
client templates posts post
Notez l attribut
.
item html
de la balise template
ù
Meteor pour garder la trace de quel template va o
é
Il est temps de pr
html simple
,
è
senter le syst
(
.
'
C est le nom qui sera utilis
:
inclusions
.
par
).
le nom du fichier n est pas important
me de templating de Meteor
avec trois choses en plus
'
é
(
é
parfois d
,
.
Spacebars
é
sign
Spacebars est du
e sous le nom de
“
”),
partials
expressions et block helpers
Les Inclusions utilisent la syntaxe
{{> templateName}} , et indiquent simplement à Meteor de
ê
remplacer le champ par le template du m
Les Expressions telles que
{{title}}
la valeur du template helper comme d
'
).
me nom
(
dans notre cas
éé
appellent une propri
t
)
postItem .
'
,
de l objet courant
é
fini dans le template manager courant
(
ou retourne
plus
d information sur ce sujet plus tard
,
Finalement
é
les block helpers sont des balises sp
{{#each}}...{{/each}}
que
ou
ô
ciales qui contr
,
lent le flux du template
{{#if}}...{{/if}} .
Aller plus loin
Vous pouvez consulter la documentation Spacebars si vous voulez en apprendre
.
plus à propos de Spacebars
é
Arm
de cette connaissance
,
é
vous pouvez dor
.
navant comprendre ce qui se passe ici
tels
è
Premi
,
rement
dans le template
{{#
avec le block helper
template
'ù
D o
'
each
postItem .
posts
vient cet objet
postsList , nous faisons des itérations sur un objet posts
}}…{{/
?
}}.
each
,
Ensuite
.
Bonne question
é
pour chaque it
'
C est un template helper
{{title}}
-
postItem
lui m
ê
me est assez simple
retournent des propri
éé
t
;
l imaginer comme un substitut à un contenu dynamique
Le template
ration nous allons inclure le
.
vous pouvez vous
.
Il utilise trois expression
: {{url}}
,
s du document
et
{{domain}}
et
appelle un template
.
helper
Template Managers
'
Jusqu à maintenant
é
balises parsem
,
é
nous avons travaill
.
es dedans
pages HTML classiques
é
logique s
'
é,
par
,
Afin d exister
s
),
- ê
qui contiennent du javascript
.
un template a besoin de helpers
é
) '
les templates
qui est du HTML avec quelques
Contrairement aux autres langages tel que PHP
dients crus
(
é
vos donn
'
,
dans les variables
,
pendant que le r
'
.
ê
me des
.
Vous pouvez imaginer ces helpers comme un
es
)
é
et les pr
ô
pare
é
le du template est limit
c est celui des helpers qui fait en r
valeur à chaque variable
ou m
me
,
avant de dresser une assiette
qu il va donner à un serveur qui va ensuite vous les pr
En d autres termes
(
Meteor garde les templates et leur
et ces templates ne font rien par eux m
chef qui prend des ingr
(
,
,
avec Spacebars
é
é
alit
'
é
senter
.
é
à l affichage et aux it
rations
le gros du travail en assignant une
Des contrôleurs ?
'
Il peut sembler tentant de penser aux fichiers contenant tous les helpers d un
template comme une sorte de
puisque les
é è
l
g
“
é
rement diff
leurs
rent
“
.
é
Nous avons donc d
simplement à
”(
ô
contr
é
cid
“
les helpers du template
,
Mais cela peut
)
ê
é
”
ou à
“
ont habituellement un r
”
la logique du template
.
,
ô
tre ambigu
éé
f
le
rer
lorsque nous
au template
nous allons nommer les fichiers contenant les helpers comme
mais avec une extension
client/templates/posts
).
controller
de ne pas utiliser cette terminologie et de nous r
Pour garder les choses simples
,
leur
du moins du point de vue MVC
parlons du code JavaScript associ
le template
”(
ô
contr
. . é
js
Cr
ons donc directement
posts_list.js
et commençons à construire notre premier helper
dans
:
var postsData = [
{
title: 'Introducing Telescope',
url: 'http://sachagreif.com/introducing-telescope/'
},
{
title: 'Meteor',
url: 'http://meteor.com'
},
{
title: 'The Meteor Book',
url: 'http://themeteorbook.com'
}
];
Template.postsList.helpers({
posts: postsData
});
/
/
/
_
client templates posts posts
'
.
list js
Si vous l avez fait correctement
navigateur
:
,
vous devriez avoir quelque choses de similaire à ça dans votre
Nos premiers templates avec données statiques
.
Nous faisons deux choses ici
tableau
è
Premi
,
rement
'
é
utilisant des donn
è
,
mement
es prototype dans le
.
nous utilisons la fonction
é posts
,
Si vous vous souvenez
)
prochain chapitre
nous allons tricher en
/
Template.myTemplate.helpers()
qui retourne le tableau
nous utilisons ce helper de
<template name="postsList">
<div class="posts page">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
/
(
es statiques
template helper appel
/
é
rons des donn
postsData . Ces données viendraient normalement de la base de données, mais
comme nous n avons pas encore vu comment faire
Deuxi
é
nous ins
_
client templates posts posts
.
list html
postsData
posts
é
d
é
pour d
finir un
.
fini auparavant
dans notre template
postsList :
é
D
finir le helper de
'
posts
,
implique qu il est maintenant disponible pour notre template
é
donc notre template sera capable de faire des it
'
d envoyer chaque objet vers le template
rations sur le tableau
postsData , et
postItem .
Commit 3-1
é
Avec le template basique de posts list et les donn
es sta
…
'
Voir sur GitHub
Lancer l instance
Le helper domain
ê
De m
me
,
é
nous allons cr
er
post_item.js
pour y renseigner la logique du template de
postItem :
Template.postItem.helpers({
domain: function() {
var a = document.createElement('a');
a.href = this.url;
return a.hostname;
}
});
/
/
/ _
client templates posts post
Cette fois la valeur du helper
è
mod
.
item js
domain
le est bien plus commun
.
simples
(
'
n est pas un tableau
)
et plus utile
é
compar
,
mais une fonction anonyme
éé
à nos pr
c
.
Ce
é
dents exemples de donn
es
Afficher les domaines pour chaque lien.
Le helper
ù
Mais o
domain
.
- '
prend une URL et retourne son domaine via un peu de magie JavaScript
prend il l url dans un premier temps
?
é
Pour r
pondre à cette question nous avons besoin de revenir à notre template
posts_list.html . Le block helper {{#each}}
,
tableau
è é
il ins
re
' '
galement les valeurs dans
é
Ça signifie qu à l int
this
rieur des deux balises
,
successivement
'é
et ça s
,
sait ce que veut dire
'
é
à l int
'
é é.
rieur du bloc de l objet it
{{#each}} , chaque article
this.url
{{title}}
et
{{url}}
this.title
et
this.url
si nous utilisons
this
rations sur notre
r
( )
é
( post_item.js ).
post
est assign
à
tend dans le manager du template inclus
Nous comprenons maintenant pourquoi
plus
é
ne fais pas seulement des it
'
'
.
retourne l URL de l article courant
dans notre template
De
post_item.html , Meteor
.
et retourne les valeurs correctes
Commit 3-2
Configurer un helper
`
`
domain
à partir du
`
`.
postItem
'
Voir sur GitHub
Lancer l instance
Magie JavaScript
é
Bien que ce ne soit pas sp
”.
JavaScript
Premi
è
,
rement
é
stockons en m
cifique à Meteor
.
,
comme nous venons de le voir
)
,
é
a
pour r
é
fonctionnalit
!
pour
ê
tre
a
avec ancre vide et la
'
é
t
é
sp
ciale
é
cup
'
gal à l URL de l article courant
éé
hostname
'
.
de l
'é é
l
ment
rer le nom de domaine du lien sans le reste de l URL
C est juste une liste de donn
suivant
'
href
nous prenons avantage de la propri
Si vous avez suivi correctement
'
(‘ ’)
Magie
l objet en cours de traitement se trouve dans un
this .
Finalement
ons une balise
“
moire
'
helper
voici une petite explication de
é
nous cr
Nous modifions ensuite l attribut
(
,
é
s temps r
,
'
.
vous devriez voir une liste d articles dans votre navigateur
é
es statiques
.
el de Meteor
,
donc ça ne tient pas compte des avantages des
Nous verrons comment changer ça dans le chapitre
Hot Code Reload
'
ê
Vous avez pu noter que vous n aviez m
ê
la fen
'
me pas eu besoin de recharger manuellement
é
tre de notre navigateur quand vous avez modifi
é
C est parce que Meteor traque tous les fichiers dans le r
î
é
rafra chit automatiquement le navigateur quand il d
'
.
vos fichiers
,
pertoire de votre projet
et
'
tecte une modification sur l un
.
d entre eux
Le Hot Code Reload de Meteor est tr
î
è
,
s intelligent
application entre deux rafra chissements
!
é
en pr
servant m
ê
'é
me l
tat de votre
Utiliser Git & GitHub
3.5
SIDEBAR
-
é ô
GitHub est un d
version Git
.
projets
,
p
é
t social pour les projets open source bas
è
et sa fonction premi
'
è
sur le syst
me de contr
ô
le de
re est de partager du code facilement et de collaborer sur des
'
.
Mais c est aussi un merveilleux outil d apprentissage
Dans cette sidebar
,
nous allons
rapidement discuter de quelques moyens pour que vous puissiez utiliser GitHub afin de suivre
.
avec Discover Meteor
é
Cet apart
suppose que vous n
,
avec les deux
vous
ê
'ê
.
tes pas familier avec Git et GitHub
tes libres de passer au chapitre suivant
!
Si vous
ê
é
tes d
'
jà à l aise
Être committed
'
é ô
Le bloc de travail de base d un d
comme une image de l
'é
p
.
t git est le commit
Vous pouvez imaginer le commit
é
.
tat de votre code à un moment donn
dans le temps
Au lieu de vous donner simplement le code fini pour Microscope
chaque
é
é
tape du d
,
Par exemple
'
veloppement
,
,
nous avons pris ces images à
.
et vous pouvez toutes les voir en ligne sur GitHub
éé
c est ce à quoi le dernier commit du chapitre pr
c
dent ressemble
:
Un commit Git vu sur GitHub.
Ce que vous voyez ici est le
“ ”(
diff
pour
“
difference
.
termes les changements introduits par ce commit
post_item.js
à partir de rien
,
”)
Dans ce cas
,
nous avons cr
é
et donc tout son contenu est surlign
Comparons avec un exemple plus loin dans le livre
'
post_item.js , en d autres
du fichier
éé
le fichier
.
en vert
:
Modifier du code.
,
Cette fois
é
seuls les fichiers modifi
,
Et bien sur
é
parfois nous n avons pas ajout
é :
supprim
'
é
s sont surlign
es
.
s en vert
é
ou modifi
,
de lignes de code
mais nous en avons
Supprimer du code.
,
Bien
è
nous venons de voir la premi
re utilisation de GitHub
:
'
avoir une vue d ensemble de ce
é.
qui a chang
Explorer le code d'un Commit
'
,
La vue d un commit de Git nous montre les changements inclus dans ce commit
'
é,
vous voudriez voir les fichiers qui n ont pas chang
doit ressembler à une
,
Une fois encore
,
commit
é
s
'
mais parfois
juste pour s assurer de ce à quoi leur code
.
tape du processus
.
GitHub a quelque chose à nous proposer
cliquez sur le bouton Browse code
:
Quand vous
ê
tes sur une page de
Le bouton Browse code.
è
Vous allez maintenant avoir acc
'
é ô
s au d
p
é
t tel qu il est à ce moment sp
cifique du commit
Le dépôt au commit 3-2.
'
GitHub ne nous donne pas d indices visuels que vous
mais vous pouvez comparer avec la vue master
“
ê
,
tes en train de regarder un commit
”
normale
'
'
et voir d un coup d oeil que la
é
structure de fichiers est diff
rente
:
Le dépôt au commit 14-2.
Accéder à un commit localement
'
.
Nous venons de voir comment explorer le code entier d un commit en ligne sur GitHub
ê
comment faire si vous voulez faire la m
me chose localement
é
vouloir ex
?
é
cuter une application localement à un commit sp
,
Par exemple
Mais
vous pourriez
cifique pour voir comment elle se
.
comportait à ce moment du processus
Pour faire ça il y a plusieurs
commande
'
é
tapes
(
,
bien
'
git . Pour les débutants, assurez vous d
)
, éé
d autres termes
t
l
)
dans ce livre du moins
charger une copie localement
'
avec l utilitaire en ligne de
é.
avoir Git install
é ô
le d
p
Ensuite clone
t de Microscope avec
:
(
en
git clone https://github.com/DiscoverMeteor/Microscope.git github_microscop
e
Ce
é
github_microscope
'
à la fin est simplement le nom du r
.
allez cloner l application
ù
Dans le cas o
é
vous avez d
pertoire local dans lequel vous
é
jà un r
pertoire
microscope , prenez
é
juste un nom diff
rent
( '
'
é
Allez dans le r
ê
il n y a pas besoin d avoir le m
pertoire avec la commande
cd
p
t GitHub
'
afin de pouvoir utiliser l utilitaire en ligne de
git :
commande
).
é ô
me nom que le d
cd github_microscope
Quand nous avons clon
'
,
é
é ô
le d
,
éé
t de GitHub
nous avons t
l
é
charg
tout le code de
.
l application
ce qui veut dire que nous avons le code du dernier commit
,
Heureusement
il y a un moyen de revenir dans le temps et de
é
sp
p
.
cifique sans affecter les autres
Essayons
:
“
”
consulter
un commit
git checkout chapter3-1
Note: checking out 'chapter3-1'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at a004b56... Added basic posts list template and static data.
Git vous informe que vous
Git a
éé
t
é,
utilis
ê
tes dans un
é
tat
“
”,
detached HEAD
vous pouvez observer les commits pass
é
'
ce qui signifie qu aussi loin que
.
s mais vous ne pouvez les modifier
Vous pouvez imaginer ça comme un sorcier en train de consulter le pass
é
dans sa boule de
.
cristal
(
Notez que Git a
é
galement des commandes qui vous laisse modifier des commits pass
é
serait plus comme un voyageur du temps qui revient dans le pass
é
craser un papillon
,
'
mais c est hors du champ de cette br
è
é.
s
Ça
et peut potentiellement
)
.
ve introduction
chapter3-1
La raison pour laquelle vous avez pu simplement taper
é
tagg
tous les commits de Microscope avec le marqueur de chapitre correcte
,
le cas
,
vous auriez besoin de trouver le hash du commit
Une fois encore
,
GitHub nous simplifie la vie
'
coin en bas à droite du champ d ent
ê
.
-
est que nous avons pre
.
'é
Si ça n
ou un identifiant unique
.
tait pas
Vous pouvez trouver un hash de commit dans le
,
te de commit bleu
-
comme ci dessous
:
Trouver un hash de commit.
'
Testons avec un hash au lieu d un tag
:
git checkout c7af59e425cd4e17c20cf99e51c8cd78f82c9932
Previous HEAD position was a004b56... Added basic posts list template and st
atic data.
HEAD is now at c7af59e... Augmented the postsList route to take a limit
,
Et finalement
ê
si nous voulons arr
é
voulons revenir dans le pr
git checkout master
sent
?
ter de regarder dans notre boule de cristal et que nous
Nous demandons à Git de consulter la branche master
:
'
Notez que vous pouvez lancer l application avec la commande
lorsque vous
ê
'é “
tes dans l
meteor update
tat
”.
detached HEAD
pas inclus dans le repo Git de Microscope
-ê
Vous aurez peut
,
si Meteor se plaint de paquets manquant
, ê
meteor
à tout moment
'
m
me
tre besoin de lancer d abord
'
puisque le code des packages n est
.
Perspective historique
Voici un autre sc
'
é
nario commun
vous n aviez pas vu avant
é.
chang
.
:
vous regardez un fichier et remarquez des changements que
,
Le fait est
que vous ne vous souvenez plus quand le fichier a
’
é
è
“
t
,
Vous pourriez juste regarder les commits un par un jusqu à que vous trouviez le bon
,
rement
":
History
é
acc
'
é ô
dez à l un des fichiers de votre d
p
.
d historique de GitHub
mais il y a un moyen plus facile grâce à la fonctionnalit
Premi
'
éé
,
t sur GitHub
puis localisez le bouton
Bouton History de GitHub.
é
Vous avez maintenant une liste claire de tous les commits qui ont affect
particulier
:
s ce fichier en
Afficher l'historique d'un fichier.
Le jeu du blâme
é
Pour d
,
velopper
è :
regardons Blame de plus pr
Bouton Blame de GitHub.
s
é
Cette vue claire nous montre ligne par ligne qui a modifi
'
,
d autres termes
le fichier
,
et dans quel commit
):
qui est à blâmer quand les choses ne fonctionnent plus
(
en
Vue Blame de GitHub.
Git est un outil assez complexe
.
tout dans un seul chapitre
.
-
et GitHub aussi
,
En fait
Mais heureusement
.
mesure du livre
é
donc nous ne pouvons pas esp
é
nous avons à peine effleur
, ê
avec ces outils
-,
m
me ce petit
é
rer couvrir
la surface de ce qui est possible
é
chantillon prouvera son utilit
au fur et à
Collections
4
Dans le chapitre un
,
nous avons parl
automatique des donn
é
'
é
d une fonctionnalit
é
é
es sp
é
é
ciale qui prend soin de conserver vos donn
, ôé
e permanente MongoDB
é
c
t
,
serveur
et qui ensuite la synchronise en
é.
é
allons commencer par cr
Les collections sont un
'
é
é Posts
er une collection appel
e
l
é
posts.js
jà fait
, é
cr
.
dedans
,
é
collections/
pertoire
Finalement ajoutez
dans
:
.
lib collections posts js
'
Commit 4-1
'
Ajout d une collection d articles
Voir sur GitHub
'
.
'
pour s assurer
lib , donc, si vous ne
lib , et ensuite un fichier
Posts = new Mongo.Collection('posts');
/
,
ainsi
finies en premier on les placera dans le dossier
ez un r
donc nous
pour les stocker dedans
ment central quelle que soit l application
é
l avez pas d
,
s entre les utilisateurs
'
éé
qu elles sont toujours d
/
es
el avec chaque navigateur connect
Nous voulons que nos articles soient permanents et partag
'
la synchronisation
.
é
temps r
,
es entre le client et le serveur
Une collection est une structure de donn
dans la base de donn
coeur de Meteor
Lancer l instance
Var ou pas Var ?
Dans Meteor
,
-
le mot cl
é var
voulons rendre la collection
’
'
.
limite le champ d un objet au fichier courant
Posts
'
è ,
disponible dans l application enti
-
raison pour laquelle nous n utilisons pas le mot cl
é
re
é
le diff
rent
.
é
:
moire du navigateur
'
.
,
:
'
ce qui signifie qu elle ne sont pas permanentes
,
Le stockage du navigateur
é
les choses comme les variables JavaScript sont stock
sont locales à l onglet courant du navigateur
fermez
î
elles
t que vous le
é
les navigateurs peuvent aussi stocker des donn
é
es perdureront session apr
(
es
ô
et dispara tront aussit
.
re permanente en utilisant des cookies ou le stockage local
donn
:
è
mani
chacune
:
moire du navigateur
dans la m
es
é
La m
'
et c est la
é ,
ô
nous
var ici
Les applications web disposent de trois façons basiques de stocker des donn
correspondant à un r
,
Ici
è
,
s session
mais disponibles dans tous les onglets
.
)
'
es de
Bien que ces
elles sont locales à l utilisateur courant
et ne peuvent pas
ê
é
tre partag
es facilement
entre les utilisateurs
La base de donn
'
é
ôé
es c
t
serveur
:
é
le meilleur endroit pour stocker des donn
'
es que
l on veut aussi rendre accessibles à plus d un utilisateur est la bonne vieille base de
é
donn
e
(
MongoDB
é
é
tant la solution par d
,
Meteor utilise les trois façons
(
comme nous le verrons bient
é :
donn
es
faut pour les applications Meteor
é
et synchronisera parfois les donn
)
ô .
t
,
Cela dit
é
la base de donn
'
es d un endroit à l autre
e reste la source
é .
elle contient la copie originale de vos donn
).
'
“
”
canonique
de
es
Client & Serveur
é
Le code contenu dans des dossiers diff
.
deux contextes
,
Cependant
Ainsi
'
,
la collection
rents de
Posts
client/
/serveur
ou
é
sera lanc
dans les
.
est disponible à la fois sur le client et sur le serveur
ce qu elle fait dans chaque environnement peut
ê
é
tre bien diff
.
rent
,
Sur le serveur
,
MongoDB
é
la collection à pour objectif de communiquer avec la base de donn
et de lire et
é
.
crire chaque changement
,
Dans cette optique
ê
elle peut
es
é
tre compar
é .
à une librairie standard de base de donn
,
En revanche
sur le client
canonique collection
,
ensemble
(
.
,
e
'
-
é
la collection est une copie d un sous ensemble de la r
ôé
La collection c
)
la plupart du temps
t
elle et
client est constamment mise à jour avec ce sous
è
de mani
re transparente
.
-
e
Console vs Console vs Console
,
Dans ce chapitre
,
nous allons commencer à utiliser la console du navigateur
,
faut pas confondre avec le terminal
'
rapide de chacuns d entre eux
.
le shell Meteor ou le shell Mongo
.
Terminal
Le Terminal
é
Appel
ôé
C
t
serveur
'
è
par votre syst
.
me d exploitation
console.log()
.
affiche la sortie ici
é: $ .
Invit
Egalement connu comme
:
Console Navigateur
,
Shell
.
Bash
'
qu il ne
Voici un topo
La console navigateur
é
Appel
ôé
C
t
client
é:
Invit
,
depuis le navigateur
❯
console.log()
é
ex
.
cute du code JavaScript
.
affiche la sortie ici
.
Egalement connu comme
:
,
Console JavaScript
.
Console Devtools
Shell Meteor
Le Shell Meteor
Le Shell Meteor
é
Appel
depuis le terminal avec
è
Il vous donne un acc
é: > .
Invit
Shell Mongo
meteor shell .
ôé
s direct au code c
t
.
serveur de votre application
Le Shell Mongo
é
Appel
meteor mongo .
depuis le terminal avec
'
è
Vous donne l acc
'
é
s direct à la base de donn
.
e de l application
é: > .
Invit
Egalement connu comme
:
,
Notez que dans chaque cas
($, ❯,
or
)
>
'ê
vous n
éé
c
éé
tes pas suppos
.
comme partie de la commande
'
é
qui ne commencent pas avec l invit
pr
.
Console Mongo
.
è
crire le caract
'
é
re de l invit
Et vous pouvez deviner que les lignes
sont la sortie
(é
r
)
sultat
de la commande
dente
Collections côté Serveur
Revenons sur le serveur
;
ôé
Dans votre code c
t
Posts.insert()
ou
posts
,
serveur
'é
ça vous permet d
.
é
'
,
e Mongo
é
toujours en cours d ex
.
crire des commandes Mongo telles que
es dans Mongo
Pour regarder dans la base de donn
application
.
e Mongo
Posts.update() , et et elles feront les changements dans la collection
é
stock
é
la collection agit comme une API dans votre base de donn
,
Ensuite
ouvrez un second terminal
),
cution sur votre premier
é
ex
cutez la commande
meteor mongo
lequel vous pouvez taper des commandes Mongo standards
pouvez quitter avec le raccourci clavier
)
é
et allez dans le r
( meteor
est
pertoire de votre
,
pour initier un shell Mongo
(
,
et comme habituellement
dans
vous
ctrl+c . Par exemple, insérons un nouvel article :
meteor mongo
> db.posts.insert({title: "A new post"});
> db.posts.find();
{ "_id": ObjectId(".."), "title" : "A new post"};
Le Shell Mongo
Mongo sur Meteor.com
'
é
Notez qu en h
acc
é
bergeant votre application sur
*.
é
der au shell Mongo de votre application h
Et pendant que vous y
ê
tes
,
votre application en tapant
La syntaxe de Mongo est famili
vous pouvez
é
.
Meteor com
,
e avec
galement retrouver les journaux
meteor logs myApp .
è ,
re
pas plus de manipulation de donn
'
.
vu qu elle utilise une interface JavaScript
é
é
,
es dans le shell Mongo
'
temps en temps pour vous assurer de ce qui s y trouve
galement
meteor mongo myApp .
é
berg
vous pouvez
( )
logs
de
Nous ne ferons
mais vous pourrez y jeter un oeil de
.
Collections côté Client
Les collections sont plus int
é
ôé
ressantes c
.
t
client
,
Mongo.Collection('posts');
sur le client
ôé
t
client en tant que
é ,
donn
es
“
é
”,
cache
è
et offre un acc
ê
ce que vous
local dans le navigateur de la collection Mongo r
c
é
Quand vous d
elle
.
'
clarez
Posts = new
é
tes en train de cr
er est un cache
'
Quand nous parlons d une collection
-
nous voulons dire qu elle contient le sous ensemble de vos
é .
s rapide à ces donn
es
Il est important de comprendre ces points qui sont fondamentaux dans la façon dont Meteor
fonctionne
.
é é ,
En g
n
é
documents stock
ral
ôé
une collection c
t
s dans la collection Mongo
envoyer toute la base de donn
é
-
client consiste en un sous ensemble de tous vos
).
es au client
(
apr
è
,
s tout
é é ,
en g
n
ral
nous ne voulons pas
è
Deuxi
'
,
mement
qu y acc
é
ces documents sont stock
é
é.
der est tout simplement instantan
ou la base de donn
,
client
é
é
es pour r
vu que les donn
cup
é
é
es sont d
é
é
-
é
'
moire du navigateur
ce qui signifie
Donc il n y a pas de longs trajets vers le serveur
rer les donn
jà pr
,
é
s dans la m
es quand vous appelez
Posts.find()
sur le
é .
charg
es
Présentation de MiniMongo
'
é
L impl
ôé
mentation de Mongo c
é
une impl
t
,
mentation parfaite
'
.
client s appelle MiniMongo
'
'
C est n est pas encore
.
occasionel de Mongo qui ne fonctionneront pas dans MiniMongo
les fonctionnalit
é
et vous pourrez rencontrer quelques fonctionnalit
,
Cependant
s
toutes
é
s qui sont dans ce livre fonctionne de façon similaire dans Mongo et
.
MiniMongo
Communication Client-Serveur
é
La cl
û
de vo
la collection c
Plut
ôé
t
serveur du m
'
ô
t que d expliquer ça en d
Commençons par ouvrir
'
.
l une des deux
,
À ce moment
contextes
éé
pr
c
(
ôé
te de tout ça est comment la collection c
,
Ensuite
2
fen
ê
me nom
é
,
tail
ê
( 'posts'
t
).
'
,
é
et acc
.
der à la console du navigateur dans
ouvrez le shell Mongo dans le terminal
vous devriez pouvoir trouver le document cr
'
es avec
dans notre cas
regardons juste ce qu il se passe
tres de navigateur
é
client synchonise ses donn
.
éé é é
pr
c
demment dans les trois
notez que l interface utilisateur de notre application affiche toujours nos trois
dents posts factices
.
-
> db.posts.find();
{title: "A new post", _id: ObjectId("..")};
Le Shell Mongo
).
Ignorez les pour le moment
Posts.findOne();
{title: "A new post", _id: LocalCollection._ObjectID};
❯
Console du premier navigateur
é
Cr
'
ons un nouvel article
d insertion
.
'
,
Dans l une des consoles de navigateur
:
é
ex
cutez une commande
❯
1
Posts.find().count();
Posts.insert({title: "A second post"});
'xxx'
❯ Posts.find().count();
2
❯
Console du premier navigateur
'
,
Sans surprise
l article a
é é éé
t
cr
.
dans la collection local
Maintenant v
é
rifions Mongo
:
db.posts.find();
{title: "A new post", _id: ObjectId("..")};
{title: "A second post", _id: 'yyy'};
❯
Le Shell Mongo
Comme vous pouvez le voir
'é
besoin d
avons
tout
!
é
,
'
l article a
é é éé
t
'
cr
crire une seule ligne de code d envoi au serveur
crit une seule ligne de code
é
dans la base de donn
(
,
bien
,
es Mongo
)
: new Mongo.Collection('posts') .
ê
Ouvrez la fen
❯
2
tre du second navigateur et entrez ceci dans la console
Posts.find().count();
,
strictement parlant
:
'
sans qu on ait
'
nous
Mais ce n est pas
Console du second navigateur
'
L article est ici aussi
!
avec le second navigateur
.
mises à jour
é
'
C est arriv
vident plus tard
é
Ce qui est arriv
'
'
ê
Quand bien m
é
,
par magie
–
é
et instantan
ôé
est que la collection c
,
é
et nous avons certainement pas
.
d un nouvel article
î
t
,
ment aussi
serveur a
'
éé
t
et a pris en charge la tâche d ins
'
bien que ça devienne plus
é
ôé
inform
'
é
é
é
cup
par la collection c
t comment lier les donn
,
es dans nos templates
simple prototype HTML en application web temps r
é
client
é
'
é
t
rer l article dans la base de donn
è
rer les articles dans la console du navigateur n est pas tr
ô
bient
me interagit
crit de code pour envoyer les
post
Mongo et de renvoyer l information à toutes les autres collections
R
ê
me nous n avons jamais rafra chit ou m
s utile
.
es
é .
connect
es
Nous apprendrons
é
et par cons
quent modifier notre
.
el fonctionnelle
Remplir la base de données
Regarder le contenu de nos collections sur le navigateur est une chose
'
é ,
aimerions vraiment faire c est afficher les donn
l
'é
.
cran
,
en application web temps r
é
é .
es
é
'
Nous allons faire ça avec un fichier d installation
es structur
è
,
es changeantes
é
re chose que nous allons faire est de mettre des donn
é
Premi
é ,
et les changements de ces donn
el avec des donn
è
La premi
donn
mais ce que nous
es
sur
En faisant ça nous transformerons notre simple page web affichant du contenu
statique
donn
es
,
,
rement
é
es dans la collection
Posts
(
.
es dans notre base de
fixture
)
é
quand le serveur d
' '
dynamiques
qui charge un ensemble de
è
marre pour la premi
é .
assurons nous qu il n y a rien dans la base de donn
es
Nous utiliserons
meteor reset , qui vide votre base de données et remet à zéro votre projet. Bien sûr, vous
é
serez vraiment vigilant avec cette commande une fois que vous aurez commenc
é
sur des projets r
ê
Arr
à travailler
.
els
tez le serveur Meteor
(
en faisant
ctrl-c
)
et ensuite
,
dans le terminal
,
é
ex
cutez
:
.
re fois
meteor reset
é .
La commande reset vide la base de donn
il y a de fortes probabilit
es
é
'
é
C est une commande utile en d
é
s que votre base de donn
Relançons notre application Meteor
é
es soit dans des
, ù
veloppement
.
tats inconsistants
:
meteor
é
Maintenant que la base de donn
es est vide
,
vous pouvez ajouter le code suivant qui va
é
charger trois articles quand le serveur va d
marrer si la collection
Posts
if (Posts.find().count() === 0) {
Posts.insert({
title: 'Introducing Telescope',
url: 'http://sachagreif.com/introducing-telescope/'
});
Posts.insert({
title: 'Meteor',
url: 'http://meteor.com'
});
}
Posts.insert({
title: 'The Meteor Book',
url: 'http://themeteorbook.com'
});
/
.
server fixtures js
Commit 4-2
é
Ajout de donn
.
es dans la collection posts
Voir sur GitHub
'
Lancer l instance
est vide
:
o
é
Nous avons plac
'
é
ce fichier dans le r
.
navigateur d un utilisateur
'
pertoire
é
Le code sera ex
et fera des appels d insertion
( insert )
server/ , il ne sera donc jamais chargé dans le
é
é
cut
imm
é
diatement quand le serveur d
é
sur la base de donn
marrera
,
es pour ajouter les trois articles
Posts .
dans notre collection
meteor , et ces trois articles seront chargés dans la
Maintenant relancez votre serveur avec
é .
base de donn
es
Des données dynamiques
,
Si nous ouvrons une console navigateur
MiniMongo
é
nous verrons les trois articles charg
s dans
:
❯
Posts.find().fetch();
Console navigateur
,
Pour afficher ces trois articles dans le rendu HTML
3
Dans le chapitre
(
contexte de donn
nous utiliserons un template helper
nous avons vu comment Meteor nous permettait de joindre un data context
é
structures de donn
)
es
à nos templates Spacebars pour construire des vues HTML de simple
é .
es
é
Nous pouvons joindre nos donn
ê
es de collections de la m
Nous remplacerons simplement notre objet JavaScript statique
dynamique
.
postsData
.
me façon
par une collection
.
,
En parlant de ça
vous
devrait ressembler
ê
tes libres de supprimer le code
posts_list.js
maintenant
:
postsData
'
.
à partir d ici
Voici à quoi
Template.postsList.helpers({
posts: function() {
return Posts.find();
}
});
/
/
/
_
client templates posts posts
.
list js
Commit 4-3
Affichage de collection dans le template
`
`.
postsList
'
Voir sur GitHub
Lancer l instance
Chercher & Récupérer
Dans Meteor
é
r
.
active
fetch()
'
A l int
'
retourne un cursor
é
Quand nous voulons r
curseur
),
é
qui est une source de donn
,
rer son contenu
es
nous pouvons utiliser
.
,
rieur d une application
Meteor est assez intelligent pour savoir comment
'
.
rer sur un curseur sans avoir à les convertir d abord explicitement en tableaux
C est pourquoi vous ne verrez pas
actuel
Plut
é
cup
(
sur ce curseur pour le transformer en tableau
'
é
é
it
, find()
(
'
fetch()
si souvent que ça dans le code Meteor
'
-
).
et pourquoi nous ne l utiliserons pas dans l exemple ci dessous
'
ô
,
t que de prendre une liste d articles sous forme de tableau statique depuis une variable
nous retournons maintenant un curseur de notre helper
'
î
é
n appara tront pas vraiment diff
é
donn
):
es
posts
(
bien que les choses
remment puisque nous utilisons toujours les m
ê
mes
Utiliser des données dynamiques
Notre helper
ôé
c
t
{{#each}}
é
serveur a r
éé
cup
r
éé
a it
r
,
les articles de Mongo
é
les a envoy
é
nos helpers Spacebars les ont affich
,
Maintenant
t
,
client
et
.
;
ajoutons un autre article via la console
:
Posts.insert({
title: 'Meteor Docs',
author: 'Tom Coleman',
url: 'http://docs.meteor.com'
});
❯
Console navigateur
–
ôé
s vers la collection c
s dans notre template
nous pouvons aller un peu plus loin
Regardez dans le navigateur
'
Posts , et les a affiché à l écran. La collection
sur tous nos
vous devriez voir ça
:
Ajout d'articles via la console
é
Vous venez juste de voir la r
é
activit
é
Spacebars qui it
rait sur le curseur
,
changements sur le curseur
'é
é
donn
es correctes à l
è
en action pour la premi
.
re fois
Quand nous parlions de
Posts.find() , il savait comment observer les
é
et a corrig
le HTML de la plus simple façon pour afficher les
.
cran
Inspecter les changements du DOM
,
Dans ce cas
'
<div
le plus simple changement possible est d ajouter un autre
class="post">...</div> . Si vous voulez vous assurer du changement, ouvrez
'
é
l inspecteur du DOM et s
<div>
lectionnez le
correspondant à un des articles
.
existants
,
Maintenant
'
,
,
sur l inspecteur
,
article
é
dans la console JavaScript
vous allez voir un
<div>
éé
l
ments ont
me
t
.
rez un autre article
é
suppl
<div>
ê
éé
mais vous aurez encore le m
utile de voir quand les
ins
-
,
é
mentaire
existant s
Quand vous revenez
correspondant au nouvel
é.
éé
lectionn
re rendus et quand ils ont
Connecter les collections : Publications et Souscriptions
t
'
C est un moyen
é
laiss
.
s seuls
é
Depuis le d
,
but
.
applications en production
ê
collection doit
autopublish
nous avons le paquet
Comme son nom l indique
é
tre partag
nous voulons vraiment
,
'
activ
é
e dans sa totalit
é
donc d
Ouvrez un nouveau terminal
,
sactivons le
et tapez
,
é,
'
é
qui n est pas conseill
pour les
ce paquet dit simplement que chaque
é.
à chaque client connect
'
Ce n est pas ce que
.
:
meteor remove autopublish
'
L effet est instantan
é.
tous vos posts ont disparus
'
,
Si vous regardez dans votre navigateur maintenant
! '
C est parce que nous nous reposions sur
ôé
s assurer que la collection posts c
t
client
vous verrez que
autopublish
pour
é
tait un mirroir de tous les articles dans la base de
é .
donn
e
é
Eventuellement nous allons avoir besoin de nous assurer que nous transf
'
articles que l utilisateur a besoin de voir
).
pagination
sa totalit
é.
'
Mais pour l instant
,
Pour faire cela
les posts
nous cr
,
(
en prenant en compte les choses comme la
nous allons juste configurer
é
ons une fonction
rons seulement les
publish()
Posts
'
é
pour qu il soit publi
éé
qui retourne un curseur r
f
dans
rençant tous
:
Meteor.publish('posts', function() {
return Posts.find();
});
/
.
server publications js
,
Dans le client
.
nous avons besoin de souscrire à la publication
suivante au fichier
main.js :
Meteor.subscribe('posts');
Nous allons ajouter la ligne
/
.
client main js
Suppression de
Commit 4-4
`
`
autopublish
é
,
rifions le navigateur
…
'
Voir sur GitHub
Si nous v
'
et mise en place d une publi
Lancer l instance
nos articles sont de retour
.
Pfiou
!
Conclusion
' -
'
Donc qu est ce qu on a fait
?
'
.
nous avons maintenant est une application web fonctionnel
,
application sur Internet
et
(
'
Bien que nous n avons pas encore d interface utilisateur
î
'
)
ce que
é
Nous pourrions d
en utilisant la console du navigateur
,
ployer cette
commencer à poster des
nouvelles histoires et les voir appara tre dans les navigateurs d utilisateurs partout à travers le
monde
.
Publications et Souscriptions
4.5
SIDEBAR
Publications et souscriptions sont un des concepts les plus importants et fondamentaux dans
Meteor
,
mais peut
ê
é
tre difficile à se repr
'
Cela a conduit à beaucoup d incompr
é
senter quand on d
é
,
hensions
é
les applications Meteor ne peuvent pas g
bute
.
'
telles que Meteor n est pas s
é
rer une large quantit
é
é,
curis
ou que
é .
de donn
es
Une grande part de la raison pour laquelle les gens trouvent ces concepts un peu perturbants
est la
“
magie
”
.
que Meteor fait pour nous
è
elle peut obscurcir ce qui se passe vraiment en arri
).
faire
-
re plan
é
D
'
é
Bien que cette magie est d une aide consid
(
,
rable
comme la magie a tendance à le
'
.
taillons un peu les couches de magie pour essayer de comprendre ce qu il se passe
Les vieux jours
,
Mais dans un premier temps
'é
n
tait pas encore là
.
,
,
re dans les vieux jours de
é
Disons que vous d
utilisateur atteint votre site
application
è
regardons en arri
(. .
le client
.
i e
)
votre navigateur
.
ê
envoie une requ
é
Le premier travail de l application est de trouver quelles donn
Ça pourrait
ê
tre à la page
,
derniers tweets de Bob
12
.
etc
de vos r
é
sultats
,
Quand un
te à votre
'
.
es l utilisateur a besoin de voir
les informations de profil de Marie
,
20
les
Vous pouvez imaginer un marchand de livres recherchant dans
é
des all
quand Meteor
veloppez une simple application Rails
qui est en cours sur votre serveur
'
2011
é.
es le livre que vous avez demand
Une fois que les bonnes donn
traduire ces donn
).
é
es ont
éé é
t
s
é ,
lectionn
es
'
le second travail de l application est de
é
es dans un joli HTML lisible par un humain
(
'
ou en JSON dans le cas d une
API
é
Dans la m
'
.
d acheter et le mettre dans un joli sac
-
,
taphore du marchand de livre
).
View Controller
'
vous pouvez envelopper le livre que vous venez juste
C est la partie
“ ”
vue
è
du fameux mod
le MVC
(
-
Model
,
Finalement
'
'
l application est termin
,
virtuelles
'
l application prend du code HTML et l envoie au navigateur
é,
Le travail de
et maintenant que toutes ces choses sont sorties de ses mains
é
elle peut se d
.
è
tendre avec une bi
ê .
re et attendre la prochaine requ
te
La vision Meteor
é
Regardons ce qui rend Meteor si sp
é
cl
'
.
cial en comparaison
'
,
de Meteor est que là ou l application Rails vit seulement sur le serveur
Meteor inclut
).
é
ôé
galement un composant c
t
'
,
Comme nous l avons vu
'
é
client qui va s ex
l innovation
une application
cuter sur le client
(
le
navigateur
Envoyer un sous-ensemble de la base de données au client.
'
C est comme un marchand qui non seulement vous trouve le livre
chez vous pour vous le lire au moment de dormir
(
,
mais aussi vous suit jusque
î
ce qui peut para tre un peu bizarre à
entendre
).
Cette architecture laisse Meteor faire des choses sympathiques
.
que Meteor appelle database everywhere
de votre base de donn
é
,
é
se d
brouiller avec ça
é
donn
é
es instantan
vers le serveur
(
-
Meteor va prendre un sous ensemble
.
es importantes
:
è
premi
,
rement
une application Meteor va envoyer la donn
client
parmi lesquelles la principale
es et le copier sur le client
é
Cela implique deux id
,
Simplement
,
(
).
è
data on the wire
ê
ment et m
Deuxi
'
au lieu d envoyer du code HTML au
é
, é
e brute
,
mement
v
,
ritablement
et laisser le client
vous allez pouvoir acc
é
der aux
-
me les modifier sans avoir à attendre un autre aller retour
).
latency compensation
Publier
Une base de donn
lesquels peuvent
'
é
ê
é
tre priv
copier notre base de donn
s ou sensibles
é
.
'
Donc nous n allons
,
es sur le client
é
Par cons
,
es d application peut contenir des dizaines de milliers de documents
'
é
es peut
.
ê
é
tre envoy
é
,
au client
è
videmment pas enti
é
pour des raisons de s
quent nous allons avoir besoin d une m
ensemble de donn
é
é
curit
'
rement
é.
et d adaptabilit
-
thode pour dire à Meteor quel sous
'
'
'
et nous l effectuerons à l aide d une
publication
.
Revenons à Microscope
é :
donn
es
'
Nous avons ici tous les articles de l application dans notre base de
Tous les articles contenus dans la base de données.
Bien que cette fonctionnalit
que certains articles ont
éé
dans notre base de donn
).
é
envoy
t
é
é
signal
é ,
es
'
n est pas encore pr
sente dans Microscope
s pour langage abusif
ils ne devront pas
ê
.
,
nous allons imaginer
Bien que nous voulons les garder
tre rendus disponibles aux utilisateurs
(. .
i e
s au client
è
Notre premi
.
au client
é :
signal
é
s
é
re tâche sera de dire à Meteor quelles donn
é
es nous voulons r
ellement envoyer
Nous allons dire à Meteor que nous voulons seulement publier les articles non
Exclure les articles signalés.
,
Voici le code correspondant
é
qui r
sidera sur le serveur
:
// on the server
Meteor.publish('posts', function() {
return Posts.find({flagged: false});
});
' '
'
'
é
Cela assure qu il n y a aucun moyen possible qu un client soit capable d acc
é.
signal
'
é
C est exactement comme ça que vous allez s
é
vous juste que vous publiez seulement les donn
der à un article
curiser une application Meteor
.
es que vous voulez fournir au client
:
-
assurez
DDP
,
ù
è
Fondamentalement
vous pouvez imaginer le syst
comme un tunnel o
transitent les donn
ôé
la collection c
t
client
(
Le protocole qui est parl
é
).
ôé
es de la collection c
t
serveur
(
source
)
vers
cible
é
dans ce tunnel est appel
,
Pour en savoir plus sur DDP
é
DDP
(
é
(
un des cr
).
Distributed Data Protocol
é
vous pouvez visionner cette pr
time Conference par Matt DeBergalis
vid
/
me de publication souscription
-
sentation de la Real
é
ateurs de Meteor
),
ou cette capture
é
o par Chris Mather qui parcourt ce concept dans les moindres d
.
tails
Souscrire
ê
Quand bien m
me nous voulons rendre les articles non signal
'
é
.
nous ne pouvons pas envoyer des milliers d articles en une fois
é,
donn
'
'
é
é
é
cifier aux clients quel sous ensemble de donn
'
Nous avons besoin d un
es ils ont besoin à un moment
.
et c est exactement là que les souscriptions interviennent
Les donn
l impl
-
é
moyen de sp
,
s disponibles pour les clients
é
es auxquelles vous souscrivez seront dupliqu
ôé
mentation Meteor de MongoDB c
,
Par exemple
t
es sur le client grâce à Minimongo
.
client
,
disons que nous sommes en train de naviguer sur la page de profil de Bob
nous voulons seulement afficher ses articles
.
et
,
Souscrire aux articles de Bob les copiera sur le client.
è
Premi
,
rement
è
nous modifierons notre publication pour prendre un param
tre
:
// on the server
Meteor.publish('posts', function(author) {
return Posts.find({flagged: false, author: author});
});
é
Et nous d
è
finirons ensuite ce param
dans le code c
ôé
t
tre au moment de la souscription à cette publication
client de notre application
:
// on the client
Meteor.subscribe('posts', 'bob-smith');
'
'
ôé
C est de cette façon qu on rend une application Meteor adaptable c
souscrire à toutes les donn
.
besoin
,
De cette façon
é
,
es disponibles
vous allez
la taille de la base de donn
é
t
viter les surcharges m
serveur
client
:
au lieu de
on choisit les parties dont nous avons actuellement
é
ôé
es c
t
.
é
moire du navigateur quelle que soit
Trouver
'
'é
Maintenant qu il est possible d
exemple
é
en m
“
Javascript
”, “
'
” “
Ruby
et
é
tiqueter les articles de Bob dans plusieurs cat
”),
Python
“
trouver
”
(
par
on pourrait avoir envie de charger tous les articles
é
moire mais de n afficher que ceux de la cat
figure que
gories
gorie
.
“
”. '
Javascript
C est dans ce cas de
intervient
Sélectionner un sous-ensemble sur le client.
'
,
Comme nous l avons fait sur le serveur
é
s
-
nous utiliserons la fonction
Posts.find()
pour
é .
lectionner un sous ensemble de nos donn
es
// on the client
Template.posts.helpers({
posts: function(){
return Posts.find({author: 'bob-smith', category: 'JavaScript'});
}
});
é
Maintenant que nous avons une bonne id
,
souscriptions
e de quel r
ô
le jouent les publications et les
creusons un peu plus profond et observons quelques patrons
'
é
d impl
.
mentations
Autopublish
é
Si vous cr
ez un projet Meteor à partir de rien
automatiquement le paquet
Le but de
autopublish
,
application Meteor
,
le client
autopublish
è
est de rendre tr
(. .
i e
activ
)
meteor create , il aura
en utilisant
é.
Commençons par discuter de son r
é
s facile le d
é
but de d
le
veloppement de votre
é
et ce en dupliquant automatiquement toutes les donn
es du serveur vers
.
ainsi en prenant soin des publications et des souscriptions pour vous
Autopublish
ô .
Comment ça fonctionne
.
serveur
?
autopublish
Alors
é 'posts'
Supposez que vous avez une collection appel
'
sur le
enverra automatiquement chaque article qu il trouvera dans la
é
collection posts Mongo vers une collection appel
'
e
).
es
'posts'
sur le client
(
é
en consid
rant
qu il y en a un
é
donn
é
é
es sont omnipr
'
'
autopublish , vous n avez pas besoin de penser aux publications. Les
Donc si vous utilisez
sentes
,
.
et les choses sont simples
è
vidents d avoir une copie compl
'
é
te de la base de donn
.
û,
Bien s
'
r
il y a des probl
è
mes
es de l application en cache sur
chaque machine d utilisateur
Pour cette raison
'
,
é
autopublish est seulement appropri
n avez pas encore r
é é
fl
é
quand vous d
,
marrez
et que vous
.
chi aux publications
Publier des collections complètes
é autopublish ,
Une fois que vous avez supprim
é
que toutes vos donn
.
es ont disparues du client
copier ce que autopublish fait
,
vous allez rapidement vous rendre compte
Une façon simple de revenir et simplement de
é.
et de publier une collection dans sa totalit
Meteor.publish('allPosts', function(){
return Posts.find();
});
Par exemple
:
Publier une collection complète
Nous publions encore des collections compl
ô
contr
Posts
è
tes
,
mais au moins nous avons maintenant le
le sur quelles collections nous publions ou pas
mais pas
.
Dans ce cas
,
nous publions la collection
Comments .
Publier des collections partielles
ô
Le niveau de contr
'
.
le suivant est de publier seulement une partie d une collection
exemple seuls les articles qui appartiennent à un certain auteur
:
Par
Meteor.publish('somePosts', function(){
return Posts.find({'author':'Tom'});
});
Publier une collection partiellement
En coulisses
,
Si vous avez lu la documentation de publication Meteor
é
d
é
pass
'
added()
par l utilisation de
enregistrements sur le client
é
vous avez d
'
,
ready()
et
-ê
vous avez peut
é
La raison est que Meteor fournit une m
'
é
.
thodes
thode vraiment tr
?
è
s pratique
-ê
Peut
:
'
–
pour
'
é
vous l avez devin
_publishCursor()
é
somePosts
–
a retourn
,
un curseur
il appelle
.
publier ce curseur automatiquement
:
fait
é
Il v
dans une
c est exactement ce qu utilise Meteor
Quand Meteor voit que la publication
Voici ce que
,
tre pas directement
( . . Posts.find({'author':'Tom'}) )
'
.
mais si vous retournez un curseur i e
_publishCursor()
t
pour appliquer les attributs des
_publishCursor() . Vous n avez jamais vu ça utilisé
,
éé
et pour recoller ça avec les applications Meteor que
jà vu et qui n utilise pas ces m
fonction de publication
tre
ôé
rifie le nom de la collection c
t
.
serveur
-
Il prend tous les documents correspondants du curseur et envoie celui ci dans
ôé
une collection c
t
.
ê
client du m
'
me nom
(
é,
A chaque moment qu un document est ajout
curseur et
'
'
-
,
.
client
et
(
é
supprim
é,
ou modifi
.observe()
Il utilise
removed()
pour faire ça
).
il envoie
sur le
).
pour faire ça
'
nous pouvons nous assurer que l utilisateur a seulement
les articles qui l interessent
.
t
.added() , .changed()
Dans l exemple au dessus
-
ôé
ces changements à la collection c
.added()
Il utilise
(
ceux
é
crit par Tom
)
ôé
disponibles dans leur cache c
t
client
Publier des propriétés partielles
,
Nous avons vu comment publier seulement certains articles
affiner
!
mais nous pouvons continuer à
éé
Voyons comment publier seulement certaines propri
Juste comme avant
,
nous allons utiliser
nous allons exclure certains champs
:
find()
t
é
s sp
.
cifiques
,
pour retourner un curseur
mais cette fois
Meteor.publish('allPosts', function(){
return Posts.find({}, {fields: {
date: false
}});
});
Publier des propriétés partiellement
û,
Bien s
r
nous pouvons
é
.
galement combiner deux techniques
ôé
retourner tous les articles de Tom en laissant de c
t
,
Par exemple
,
leurs dates
nous
é
si nous voulions
cririons
:
Meteor.publish('allPosts', function(){
return Posts.find({'author':'Tom'}, {fields: {
date: false
}});
});
Résumé
éé
Donc nous avons vu comment publier chaque propri
collection
(
avec
autopublish
)
'
t
de tous les documents de chaque
éé
jusqu à publier seulement certaines propri
.
t
s de certains
documents de certaines collections
Ceci couvre les bases de ce que vous pouvez faire avec les publications Meteor
'
é
techniques s occuperont de la vaste majorit
,
Parfois
'
,
et ces simples
.
des cas d utilisation
'
,
vous aurez besoin d aller plus loin en combinant
Nous allons en discuter dans un prochain chapitre
!
,
reliant
.
assemblant des publications
Le Routage
5
Maintenant que nous avons une liste de posts
par des utilisateurs
auront la possibilit
),
é
'
(
qui peuvent avoir
t
é
ventuellement envoy
ù
nous avons besoin d une page pour chaque post o
de laisser des commentaires
http://myapp.com/posts/xyz
,
.
( ù xyz
o
s
les utilisateurs
.
Nous aimerions rendre ces pages accessible par un permalien
pour chaque post
é éé
une URL de la forme
est un identifiant MongoDB
'
_id
)
qui est unique
'
Cela signifie que nous allons avoir besoin d un routage pour voir ce qu il y a dans la barre URL
.
du navigateur et afficher le contenu correspondant
Ajout du package Iron Router
Iron Router est un package de routage qui a
Meteor
é é éé
cr
é
sp
cialement pour les applications
.
'
Non seulement c est une aide pour le routage
'
s occupe aussi des filtres
abonnements
é
d
t
é
velopp
(
('
(
)
l assignation de ces chemins à des actions
'
é
savoir quel chemin permet d acc
-
),
la mise en place des chemins
,
par un des co auteurs de Discover Meteor
e
)
.
Tom Coleman
Commençons par installer le package depuis Atmosphere
ê
et il s occupe m
)(
é .
der à quelle donn
'
mais le package
Note
:
me des
Iron Router a
éé
t
:
meteor add iron:router
Terminal
Cette commande va t
éé
l
é
Notez que vous devrez probablement red
,
terminer le processus
.
charger et installer le package Iron Router dans votre application
puis
meteor
marrer votre application Meteor
é
pour le red
)
marrer
(
avec
ctrl+c
avant que le package ne soit
pour
.
utilisable
Vocabulaire sur le routage
é
Nous allons aborder plusieurs fonctionnalit
é
avez d
é
jà utilis
.
'
:
'
Si ce n est pas le cas
ù
:
Segments
:
(
)
ou Path
.
'
.
est une URL de l application
( / ).
tre
, é
rentes parties qui composent un chemin
é
Les Hooks sont les actions qui seront effectu
'
.
,
es avant
cessaire pour afficher une page
é
Les filtres sont des hooks qui sont d
è
apr
Un exemple typique serait de v
é
l utilisateur a les droits n
:
ê
Il peut m
é
pendant le processus de routage
Elle peut
é
s
par
s ou m
Template de routes
,
cisez pas un
:
es
ê
me
rifier si
.
finis globalement pour une ou
.
é
me
é
plusieurs routes
pr
ê
tres
ce sont les diff
par un slash
Filtres
'
ou dynamique
y avoir des param
:
'
C est un jeu d instruction qui
( /information_legales )
( /posts/xyz ).
è
( /search?keyword=meteor ).
statique
:
aller et quoi faire pour chaque URL
un chemin
voici un glossaire pour vous aider
.
dit à l application o
Hooks
,
la route est le bloc de base du routage
Chemins
Si vous
un Framework comme Rails vous connaissez probablement la
plupart de ces concepts
Routes
.
s du routage dans ce chapitre
Chaque route doit pointer vers un template
ê
le routeur cherchera le template avec le m
.
'
Si vous n en
me nom que la
.
route
Layouts
:
é .
Vous pouvez voir les layouts comme des cadres pour vos donn
es
Ils
contiennent tout le code HTML qui entoure les templates et qui ne bougera pas
ê
m
-
ê
me si le template lui m
ô
Contr
leurs
:
,
ê
Quelques fois
é
templates r
code
,
utilisent les m
vous pouvez faire h
é.
me est modifi
vous vous rendrez compte que beaucoup de
mes param
è
é
.
tres
ô
Plut
t que de dupliquer votre
'
ê
riter toutes ces routes d un m
ô
me contr
leur de
.
routage qui contient toute la logique de routage ordinaire
'
Pour plus d information sur Iron Router
.
,
è
consultez la documentation compl
GitHub
Routage : Relier des URLS à des templates
te sur
'
é
Jusqu à pr
(
comme
é
sent nous avons construit notre layout en utilisant des inclusions cod
)
{{>postsList}} . Bien que le contenu de notre application puisse changer, la
structure de la page est toujours la m
ê
me
:
.
un titre avec une liste de posts en dessous
é
Iron Router nous laisse sortir du cadre en nous laissant changer ce qui est affich
'
<body> . Donc nous n allons pas définir le contenu de cette balise nous
HTML
.
dans une page HTML classique
A la place
,
cial qui contient un helper de template
Ce helper
{{> yield}}
me comme
finir une zone dynamique qui va automatiquement afficher le
template correspondant à la route courante
maintenant ce template sp
ê
m
{{> yield}} .
é
va d
-
dans la balise
nous allons pointer le routeur vers un template
é
sp
es en dur
é
cial le
“
(
,
par convention
template de routage
”) :
é
nous d
signerons à partir de
Layouts et templates.
Nous allons commencer par cr
è
Premi
,
rement
é
er notre layout et ajouter le helper
nous allons supprimer l
'é é
l
ment HTML
<body>
de
{{> yield}} .
main.html , et déplacer
, layout.html
son contenu vers son propre template
dossier
)
client/templates/application .
'
'
Iron Router s occupera d int
ressemble maintenant à ça
(
que nous placerons dans un nouveau
é
grer notre layout dans le template minimaliste
main.html , qui
:
<head>
<title>Microscope</title>
</head>
/
.
client main html
Le fichier
éé
layout.html
application
nouvellement cr
é
contiendra maintenant le layout ext
rieur de notre
:
<template name="layout">
<div class="container">
<header class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="/">Microscope</a>
</div>
</header>
<div id="main">
{{> yield}}
</div>
</div>
</template>
/
/
/
.
client templates application layout html
é
Vous noterez que nous avons remplac
helper
è
Apr
'
yield .
s ce changement
.
d Iron Router
'
,
'
'
l inclusion du template
postsList
'
avec un appel du
é
l onglet de notre navigateur affiche la page d aide par d
'
faut
'
C est parce que nous n avons pas encore dit au routeur que faire avec l URL
.
donc il renvoie un template vide
/,
é
Pour d
/
,
marrer
au template
é
r
pertoire
'
nous pouvons retrouver notre ancien comportement en assignant l URL racine
/lib
postList . Nous allons créer un nouveau fichier router.js
dans la racine du projet
'
é
à l int
:
rieur du
Router.configure({
layoutTemplate: 'layout'
});
Router.route('/', {name: 'postsList'});
/
.
lib router js
é
Nous avons effectu
'
.
deux choses importantes
è
Premi
é
d utiliser le layout que nous venons tout juste de cr
,
rement
nous avons dit au routeur
é
er comme layout par d
faut pour toutes
.
les routes
è
Deuxi
,
mement
é
assign
é
nous avons d
e à la racine
fini une nouvelle route appel
é postList
e
'
et nous l avons
/.
Le répertoire /lib
é
Quoi que vous mettiez dans le r
/lib , cela sera assurément chargé en
pertoire
premier avant tous les autres fichiers de votre application
).
possible les paquets intelligents
'ê
helper qui a besoin d
dans
:
avec comme exception
Ceci en fait une place de choix pour y mettre un
tre disponible en permanence
Une petite mise en garde
(
notez que le r
é
.
/lib
pertoire
'
n est ni dans
/client
ni
/server , cela signifie que le contenu sera disponible dans les deux
.
environnements
Routes nommées
'
ïé
Éclaircissons un peu l ambigu t
avons
é
.
ici
galement un template appel
é
Nous avons nomm
é postList .
notre route
' -
'
postList , mais nous
Donc qu est ce qu il va se passer ici
?
é
Par d
fait
,
,
faut
Iron Router va chercher un template avec le m
ê
il va m
é
me d
(
puisque notre chemin est
me nom que celui de la route
é
duire le nom du chemin que vous sp
dans ce cas particulier
ê
)
.
cifiez
/ , Iron Router aurait trouvé le bon
é http://localhost:3000/postsList
ê
Vous pouvez vous demander pourquoi nous avons quand m
.
.
comme chemin
me besoin de nommer nos routes
é
Nommer les routes nous laisse utiliser quelques fonctionnalit
é
Iron Router qui nous rend plus facile la cr
est le helper Spacebars
.
ation de liens dans notre application
'
é
'
cifier une URL statique
ê
sera le m
me
,
s de
La plus utile
{{pathFor}} , qui retourne l URL du composant chemin de la route.
'
,
Nous voulons que notre lien d accueil principal pointe vers la liste d articles
sp
En
Bien que cela ne marcherait pas
template si nous avions utilis
dans un premier temps
.
/ , nous allons pouvoir utiliser le helper Spacebars. Le résultat final
é
mais cela nous donne plus de flexibilit
ê
toujours la bonne URL m
donc au lieu de
è
me si nous changeons apr
puisque le helper nous renverra
-
s coup le chemin de la route dans le
.
routeur
<header class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="{{pathFor 'postsList'}}">Microscope</a>
</div>
</header>
//...
/
/
/
.
client templates application layout html
Commit 5-1
è
Routage tr
Voir sur GitHub
s basique
.
'
Lancer l instance
Attente De Données
é
Si vous d
'
ployez la version courante de l application
(
'
ou lancez l instance web en utilisant le
-
),
. '
'
î
lien au dessus
apparaissent
vous noterez que la liste appara t vide un petit moment avant que les articles
è
C est parce que quand la page se charge la premi
afficher jusqu à que la souscription aux
articles du serveur
en train de se passer
,
'
(
'
,
soit termin
e
r
'
é
cup
é
rant les donn
es des
é
rience de fournir un indicateur visuel que quelque chose est
.
et que l utilisateur doit attendre un moment
Iron Router nous donne un moyen facile de faire ça
to wait on
d attendre
é , é
articles
'
il n y a pas d articles à
.
Ce serait une bien meilleure exp
Par chance
,
re fois
)
la souscription
nous pouvons lui demander
.
é
On commence par d
:
placer notre souscription
posts
main.js
depuis
vers le routeur
:
Router.configure({
layoutTemplate: 'layout',
waitOn: function() { return Meteor.subscribe('posts'); }
});
Router.route('/', {name: 'postsList'});
/
.
lib router js
,
Ce que nous voulons faire ici
,
pour le moment
La principale diff
souscription
),
supprimer
'
'
c est que pour chaque route du site
ô
mais nous en aurons bient
t plus
!),
rence entre ceci et ce que nous avions pr
tait dans
é
'
éé
c
demment
posts .
(
lorsque la
main.js , qui devrait être dorénavant vide et que vous pouvez
est que maintenant
lorsqu elle a les donn
'
nous n en avons qu une
nous voulons souscrire à
é
é
(
,
Iron Router
“ ”
sait
quand la route est pr
.
ê
te
–' --
c est à dire
es dont il a besoin pour le rendu
Visez un peu ça
Savoir quand la route
'
postsList
'
est pr
ê
te ne nous est pas grandement utile si de toute façon
nous n allons afficher qu un template vide
'
'
.
,
Heureusement
'
é é
Iron Router inclut une proc
'
pour retarder l affichage d un template jusqu à ce que la route qui l appelle soit pr
ê ,
te
d
et
affiche un template de chargement
( loading )
à la place
:
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
waitOn: function() { return Meteor.subscribe('posts'); }
});
Router.route('/', {name: 'postsList'});
/
.
lib router js
é
Notez que puisque nous d
,
'
é
routeur
'
finissons notre fonction
cette s
,
quence ne se produira qu une fois
l application pour la premi
è
re fois
'
.
è
Apr
s cela
,
waitOn
'
globalement au niveau du
é
les donn
è
.
ce finale du puzzle est le template de chargement
pour cr
é
er un joli indicateur de chargement anim
é
et cr
chargement
ez le template de
é.
,
comme suit
é
es seront charg
du navigateur et le routeur n aura plus besoin de les attendre
La pi
é
lorsqu un utilisateur acc
dera à
es dans la m
é
moire
.
Nous allons utiliser le paquet
Ajoutez le avec
spin
meteor add sacha:spin ,
dans le dossier
client/templates/includes :
<template name="loading">
{{>spinner}}
</template>
/
/
/
.
client templates includes loading html
Notez que
partial
“
{{>spinner}}
”
ne provient pas
.
est un partial contenu dans le paquet
,
de notre application
'
spin . Quand bien même ce
'
nous pouvons l inclure comme n importe quel
autre template
'
é
C est normalement une bonne id
'
é
l exp
rience utilisateur
,
'
,
e d attendre les souscriptions
non seulement pour
,
mais aussi parce que cela signifie que vous pouvez
partir du principe que les donn
é
,
avec certitude
es seront toujours disponibles depuis un template
.
Cela
é
supprime le besoin de g
-
ù
éé
rer les cas o
,
les templates sont interpr
é
sous jacentes soient disponibles
ce qui n
t
é
s avant que leur donn
es
.
cessite souvent des astuces laborieuses
Commit 5-2
.
Attendre la souscription aux articles
'
Voir sur GitHub
Lancer l instance
Un premier aperçu sur la réactivité
La r
é
é
ativit
,
est une partie essentielle de Meteor
é,
encore vraiment touch
'
et bien que nous n y avons pas
notre template de chargement nous donne un premier
.
aperçu de ce concept
é
Rediriger vers un template de chargement si les donn
,
est vraiment bien
'
,
.
-
restons en là
'
es
mais comment le routeur sait quand rediriger l utilisateur vers la
bonne page une fois que les donn
Pour l instant
é
es ne sont pas encore charg
é
es arrivent
?
'
ù
disons juste que c est exactement o
é
Mais ne vous inqui
tez pas
,
la r
é
é
activit
,
intervient
ô
vous en apprendrez plus bient
t
et
!
Router vers un article spécifique
Maintenant que nous avons vu comment router vers le template
route pour afficher le d
'
'
é
postsList , ajoutons une
.
tail d un seul article
'
Il n y a pas qu un seul article
:
il y en aurait des milliers
.
'
é
nous ne pouvons continuer et d
,
'
sinon
,
Donc nous allons avoir besoin de mettre une seule route dynamique
'
'
et permettre à la route d afficher n importe quel article que l on souhaite
Pour commencer
,
finir une route par article
é
nous allons cr
d article que nous avons utilis
é
.
ê
er un template qui renvoie simplement le m
'
.
dans la liste d articles
me template
<template name="postPage">
<div class="post-page page">
{{> postItem}}
</div>
</template>
/
/
/ _
client templates posts post
.
page html
'é é
Nous allons ajouter plus d
'
l
ments dans le template plus tard
(
mais pour l instant il va simplement servir de coquille pour notre inclusion
Nous allons cr
é
é ,
er une autre route nomm
/posts/<ID>
forme
au template
e
),
tels que les commentaires
postItem .
'
cette fois en associant les chemins d URL de la
postPage :
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
waitOn: function() { return
Meteor.subscribe('posts'); }
});
Router.route('/', {name: 'postsList'});
Router.route('/posts/:_id', {
name: 'postPage'
});
/
.
lib router js
La syntaxe sp
'
é
ciale
:_id
dit au routeur deux choses
n importe quelle route de la forme
è
Deuxi
,
mement
tableau des
:
'
/posts/xyz/ , où
è
premi
“ ”
xyz
,
rement
peut
ê
faire correspondre
'
.
tre n importe quoi
é é _id
mettre ce qu il trouve à la place de xyz dans une propri
params
du routeur
t
dans le
.
Notez que nous utilisons seulement
_id
connaitre si ce que vous lui passez est un
.
par convention ici
'
Le routeur n a pas de moyen de
_id , ou juste une chaîne aléatoire de caractères.
,
Nous routons maintenant vers le template correct
mais il nous manque encore quelque
chose
:
î
'
.
toujours pas d indice
,
Heureusement
é
'
,
-
é
Donc comment peut on combler ce foss
'
é
es
es comme l int
simplement
de l article que nous voulons afficher
é é
le routeur a une solution int
contexte de donn
donn
’ _id
le routeur conna t l
'
é
(
data context
'
é
rieur d un d
)
gr
e intelligente
de template
.
:
?
,
'
mais le template n a
é
il vous laisse sp
cifier un
Vous pouvez imaginer le contexte de
licieux gateau fait de templates et de layouts
c est ce avec quoi vous remplissez votre template
.
Tout
:
Le contexte de données.
,
Dans notre cas
é
bas
’ _id
sur l
nous pouvons r
é
r
cup
éé
r
é
'
cup
dans l URL
é
:
é
rer le bon contexte de donn
es en regardant notre article
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
waitOn: function() { return Meteor.subscribe('posts'); }
});
Router.route('/', {name: 'postsList'});
Router.route('/posts/:_id', {
name: 'postPage',
data: function() { return Posts.findOne(this.params._id); }
});
/
.
lib router js
'
è
A chaque fois qu un utilisateur acc
.
passerons au template
ê ,
à la requ
'
te
rieur de la fonction
,
correspondante
la route
(
data
_id
é
'
é
nous trouverons l article appropri
'
, this
d une route
é
{_id: id} .
correspond à la route courante
this.params
en les pr
et le
retourne un seul article qui correspond
comme argument est un raccourci pour
et nous pouvons utiliser
que nous avons indiqu
,
findOne
Souvenez vous que
et que fournir juste un
é
A l int
-
de à cette route
fixant avec
:
é
pour acc
der aux parties nomm
).
dans notre chemin
é
es de
En savoir plus à propos des contextes de données
En initialisant un contexte de donn
this
de
é
es de template
dans les helpers de template
'
é
automatiquement le contexte de donn
'
é
ration
ô
nous pouvons contr
ler la valeur
.
'
é
C est habituellement fait implicitement avec l it
d it
,
{{#each}} , qui renvoie
rateur
é
es de chaque it
'
ration à l item en cours
:
{{#each widgets}}
{{> widgetItem}}
{{/each}}
Mais nous pouvons
simplement
pouvons
é
“
é
galement le faire explicitement en utilisant
prends cet objet
crire
,
{{#with}} , qui dit
”.
et applique lui le template suivant
:
,
Par exemple
nous
{{#with myWidget}}
{{> widgetPage}}
{{/with}}
'
è
Il s av
re que vous pouvez obtenir le m
'
.
argument dans l appel de template
comme suit
:
ê
é
me r
sultat en passant le contexte comme
Et donc le code pr
éé
c
dent peut
ê
tre r
éé
crit
{{> widgetPage myWidget}}
é
Pour une exploration plus pouss
lire notre article de blog
(
é
e des contextes de donn
)
en anglais
é
es nous vous sugg
rons de
.
sur ce sujet
En utilisant un Route Helper Dynamique Nommé
,
Enfin
nous allons cr
é
er un nouveau bouton
.
personnelle de posts
De m
ê
,
me
“
Discuter
”
qui redirigera vers notre page
nous pourrions faire quelque chose comme
'
href="/posts/{{_id}}"> , mais c est plus fiable en utilisant un route helper.
<a
é
Nous avons nomm
postPage , donc nous pouvons utiliser le helper
la route article
{{pathFor 'postPage'}} :
<template name="postItem">
<div class="post">
<div class="post-content">
<h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
</div>
<a href="{{pathFor 'postPage'}}" class="discuss btn btn-default">Discuss
</a>
</div>
</template>
/
/
/ _
client templates posts post
.
item html
Commit 5-3
'
.
Route vers la page d un article
'
Voir sur GitHub
Attendez
,
è
Apr
'
comment le routeur sait comment r
,
s tout
è
Il s av
nous ne lui passons aucun
é
é
cup
rer la partie
xyz
'
(
_id .
-
'
ê
me
.
é
_id
Donc le routeur cherchera cet
fini notre
)
de ce
path .
'
dans l endroit disponible le plus logique
'
!)
?
Nous disons au
postPage , et le routeur sait que cette route requiert un _id
vu que c est comment nous avons d
du helper
/posts/xyz
dans
re que Iron Router est assez intelligent pour le trouver par lui m
routeur d utiliser la route
type
Lancer l instance
:
le data context
{{pathFor postPage}} , en d autre mots this . Et il se trouve que notre this
'
,
correspondre à l article
Alternativement
,
lequel
vous pouvez
é é _id ,
cherche la propri
t
(
surprise
poss
è
é é _id .
de une propri
t
é
ù
galement explicitement dire au routeur o
en passant un second argument au helper
)
va
'
vous aimeriez qu il
( . . {{pathFor
i e
'postPage' someOtherPost}} . Un usage pratique de ce modèle serait de récupérer le lien
éé
des articles pr
c
dents et suivants dans une liste
Pour voir si ça fonctionne correctement
liens
‘
’.
Discuss
,
,
par exemple
.
'
naviguez dans la liste d articles et cliquez sur un des
Vous devriez voir quelque chose comme ça
:
Page d'un article.
HTML5 pushState
'
5
.
Une chose à savoir est que ces changements d URLs utilisent HTML
é
Le routeur r
è
cup
'
'é
é
de naviguer à l ext
é
n
cessaires à l
,
re les clics sur les URLs internes au site
'
,
rieur de l application
'
pushState
ê
et emp
che le navigateur
en plus de faire les changements
.
tat de l application
é
Si tout fonctionne correctement la page devrait changer instantan
'
.
ment
parfois les choses changent si vite qu une sorte de transition pourrait
'
,
C est hors du champ de ce chapitre
Article non trouvé
ê
mais un sujet tout de m
é
me int
ê
,
En fait
é
.
tre n
ressant
.
cessaire
'
N oublions pas que le routing fonctionne dans les deux sens
'
,
lorsqu on visite une page
,
Ainsi
:
'
il permet de changer l url
'
'
.
mais il peut aussi afficher une nouvelle page lorsqu on change l url
'
.
nous devons nous assurer de ce qui se passe si quelqu un entre une mauvaise url
,
Heureusement
,
En premier lieu
'
'
'
Iron Router s occupe de cela pour nous grâce à l option
notFoundTemplate .
nous allons mettre au point un nouveau template qui affiche un simple
message d erreur
404 :
<template name="notFound">
<div class="not-found page jumbotron">
<h2>404</h2>
<p>Désolé, nous ne pouvons pas trouver une page à cette adresse.</p>
</div>
</template>
/
/
/ _
client templates application not
,
Ensuite
.
found html
nous allons tout simplement lier Iron Route à ce template
:
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() { return Meteor.subscribe('posts'); }
});
//...
/
.
lib router js
'
Pour tester notre nouvelle page d erreur
comme
,
'
http://localhost:3000/rien-par-ici .
Un instant
;
--
'
é
vous pouvez essayer d acc
que se passe t il si quelqu un entre une url de la forme
http://localhost:3000/posts/xyz , où xyz
’
n estpas un
_id
der à une url quelconque
'
valide d article
? '
C est
,
toujours une route valide
,
Heureusement
é
sp
cial
è
mais elle ne m
é .
ne à aucune donn
é
Iron Router est assez intelligent pour g
dataNotFound
à la fin de
e
rer cela
,
'
il suffit d ajouter un hook
router.js :
//...
Router.onBeforeAction('dataNotFound', {only: 'postPage'});
/
.
lib router js
'
Cela indique à Iron Router d afficher la page
“
non trouv
data
invalides mais aussi à chaque fois que la fonction
null , false , undefined
ou un objet vide
).
é
”
non seulement pour les routes
Commit 5-4
Avec le template
«
Voir sur GitHub
non trouv
(
é é . .
renvoie un objet non d
sir
i e
»
é.
'
Lancer l instance
Pourquoi “Iron" ?
ù
Au cas o
'
è
d apr
éé
m
t
'
'
è
vous vous demanderiez qu elle est l histoire derri
, é
é
s Chris Mather
cr
ores sont compos
ateur de Iron Router
,
'
re le nom
"
Iron Router
cela s explique par le fait que les
es principalement de fer
(
iron en anglais
).
":
La Session
5.5
SIDEBAR
Meteor est un framework r
é
.
actif
é
Ce qui veut dire que comme les donn
,
es changent
les choses
dans votre application changent sans que vous ayez explicitement besoin de faire quoi que ce
.
soit
Nous avons d
é
donn
é
jà vu ça en action lors des changements de template à la modification de
.
es et de routes
,
Nous irons un peu plus loin dans le fonctionnement plus tard dans les chapitres
,
moment
ê
extr
nous aimerions pr
é
é é
senter quelques fonctionnalit
s r
mais pour le
actives de base qui sont
é é .
mement utiles dans les applications en g
n
ral
La Session Meteor
'
'
'
, é
Actuellement dans Microscope
'
l
contenu dans l URL qu il regarde
,
Mais dans de nombreux cas
(
tat courant de l application utilisateur est compl
é
et la base de donn
).
'
éé
l
ment soit affich
é
vous allez avoir besoin de stocker des
)
é.
ou cach
'
singleton global
:
il y a une session
,
é
'
es r
é
active
.
'
é
tats
é é è
ph
m
'
,
,
par exemple
.
al pour faire ça
'
.
Les variables globales sont
mais dans ce cas la session peut
é
utilis
(
res qui sont
C est global dans le sens d un objet
et c est accessible partout
habituellement vues comme des mauvaises choses
'
é
La session est un moyen id
La session est une zone de stockage de donn
tement
es
seulement pertinants pour la version courante de l utilisateur de l application
qu un
è
é
e comme un bus de communications central entre les diff
ê
tre
rentes parties de
.
l application
Changer la Session
'
La Session est disponible partout sur le client en tant que l objet
,
valeur de sessions
vous pouvez appeler
:
Session . Pour insérer une
❯
Session.set('pageTitle', 'A different title');
Console du navigateur
é
Vous pouvez ensuite lire les donn
é
source de donn
'
es r
é
,
active
,
et ça signifie que si vous la mettez dans un helper
changer ce qu affiche le helper de mani
,
Pour essayer ça
'
Session.get('mySessionProperty'); . C est une
es avec
è
re r
vous pouvez
é
.
active en changeant la valeur de Session
ajoutez le code qui suit au template layout
:
<header class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="{{pathFor 'postsList'}}">{{pageTitle}}</a>
</div>
</header>
/
/
/
.
client templates application layout html
Template.layout.helpers({
pageTitle: function() { return Session.get('pageTitle'); }
});
/
/
/
.
client templates application layout js
Une note sur le code des apartés
é
Notez que le code pr
.
,
principal du livre
vous utilisez Git
)
sent
é
é
dans les chapitres apart
'
,
les variables de Session
.
,
Sinon
er une nouvelle branche maintenant
(
si
.
soit vous assurez d annuler les changements à la fin de ce chapitre
Le rechargement automatique de Meteor
navbar
é
Vous pouvez donc soit cr
s ne fait pas partie du cours
(
connu comme
“
donc nous devrions voir maintenant
éé
retapez juste la pr
c
dente commande
”
hot code reload
“
”
A different title
Session.set()
)
ou HCR
é
pr
é
affich
serve
dans la
.
une nouvelle fois
,
De plus
si nous changeons la valeur une fois de plus
é
devrions voir le titre affich
(
via la console du navigateur
changer une nouvelle fois
:
),
nous
Session.set('pageTitle', 'A brand new title');
❯
Console du navigateur
La Session est disponible globalement
ù
o
'
dans l application
'
.
donc de tels changements peuvent
,
Ça nous donne un peu de pouvoir
si c est trop souvent utilis
'
,
mais ça peut
ê
galement
.
,
ê
è
tre un pi
ge
é.
me entre les onglets
nouvel onglet
'
tre fait n importe
é
'
’
'
é
D ailleurs il est important d indiquer que l objet Session n est pas partag
ou m
ê
'
'
,
entre les utilisateurs
C est pourquoi si vous ouvrez maintenant l application dans un
vous serez face à un titre de site vide
.
Changements Identiques
Si vous modifiez une variable de Session avec
'
,
l initialisez à une valeur identique
î
é
cha ne r
,
active
et
Session.set()
mais que vous
Meteor est assez intelligent pour passer outre la
é
é
vitez les appels de fonction non n
.
cessaires
Présentation de Autorun
é
Nous avons regard
'
action à l int
é
'
é
un exemple d une source de donn
'
rieur d un helper de template
)
template helpers
é
sont r
è
actifs de mani
.
ù
Mais là o
é
re inh
Meteor est encore plein de JavaScript non r
é
rentes
.
,
es r
é
,
active
'
les contextes dans Meteor
é
la majorit
é
et nous l avons observ
'
(
en
tels que les
du code de l application
actif
Supposons que nous avons le petit bout de code suivant quelque part dans notre application
:
helloWorld = function() {
alert(Session.get('message'));
}
ê
Quand bien m
é
appel
,
me nous appelons une variable de Session
é
e est non r
actif
,
'
le contexte dans lequel elle est
alerte
ce qui signifie que nous n aurons pas de nouvelle
.
à chaque
fois que nous changerons la variable
'
C est là que Autorun intervient
autorun
é
r
'
é
s ex
.
'
é
cutera et restera en cours d ex
é
actives utilis
'
es à l int
'
Comme son nom l indique
é
,
'
é
le code à l int
'
rieur d un bloc
é
cution chaque fois que les sources de donn
es
.
rieur changeront
:
Essayer de taper ça dans la console de votre navigateur
Tracker.autorun( function() { console.log('Value is : ' + Session.get('pa
geTitle')); } );
Value is : A brand new title
❯
Console du navigateur
,
Comme vous pouviez vous y attendre
'é é
s
x
titre
,
cute une fois
'
é
le bloc de code fourni à l int
é
retournant ses donn
es à la console
.
rieur du
,
Maintenant
autorun
essayons de changer le
:
❯ Session.set('pageTitle', 'Yet another value');
Value is : Yet another value
Console du navigateur
'
C est magique
!
é, autorun
Comme la valeur de session a chang
,
contenu une nouvelle fois
Revenons à notre pr
éé
c
'
a su qu il devait executer son
.
renvoyant la nouvelle valeur à la console
,
dent exemple
é
si nous voulons d
clencher une nouvelle alerte à
,
chaque fois que la variable change
'
'
tout ce dont nous avons besoin est d envelopper notre
autorun :
code d un bloc
Tracker.autorun(function() {
alert(Session.get('message'));
});
Comme nous venons de le voir
é
donn
é
es r
actives et r
é
agir
, autorun
peut
ê
tre vraiment utile pour traquer les sources de
.
Hot Code Reload
é
Durant notre d
veloppement de Microscope
Meteor qui fait gagner du temps
,
fichiers de code
Meteor d
'
é
nous avons profit
hot code reload
é
( ).
HCR
é
cution
,
'
é
d une fonctionnalit
de
Quand nous sauvegardons un de nos
é
tecte les changements et red
serveur meteor en cours d ex
'
:
,
marre de façon transparente le
en informant chaque client de recharger la page
C est identique à un rechargement automatique de la page
,
é
mais avec une diff
.
rence
.
importante
'
Pour trouver ce que c est
é :
utilis
,
commencer par r
é
initialiser la variable de session que nous avons
e
❯ Session.set('pageTitle',
❯ Session.get('pageTitle');
'A brand new title');
'A brand new title'
Console du navigateur
Si nous devions recharger la fen
ê
session seraient naturellement perdues
autre c
ô é,
t
é
si nous d
fichiers source
)
,
tre de notre navigateur manuellement
(
vu que nous cr
clenchons un hot code reload
la page se rechargera
,
(
é
nos variables de
). '
erions une nouvelle session
par exemple
,
D un
en sauvegardant un de nos
é .
mais la variable de session sera encore initialis
e
Essayez ça maintenant
!
Session.get('pageTitle');
'A brand new title'
❯
Console du navigateur
'
Donc si nous utilisons des variables de session pour tracer exactement ce que l utilisateur est
,
en train de faire
le HCR devrait
ê
'
tre transparent pour l utilisateur
.
valeur de toutes les variables de session
é
Ceci nous permet de d
'
,
é
comme ça pr
serve la
ployer en production des
nouvelles versions de notre application Meteor avec l assurance que nos utilisateurs seront
é
d
é
rang
é
Consid
.
s de façon minimale
.
,
la session
'
Si nous pouvons g
rer de garder tous les
'
é
nous pouvons changer le code source en cours d ex
è
l application de mani
'
é
tats dans l URL et
cution de chaque client de
.
re transparente et avec un impact minimal
'
é
V
é
rez ceci pour le moment
î
rifions maintenant ce qu il se passe quand nous rafra chissons la page manuellement
:
Session.get('pageTitle');
null
❯
Console du navigateur
,
Quand nous rechargeons la page
.
nous perdons la session
session en local dans le navigateur et la recharge apr
,
Cependant
,
é
é
initialis
'é
à l
'
'
c est comme s il avait encore explor
tat de d
é
'
Meteor sauvegarde la
s le rechargement de la page
le comportement alternatif d un rechargement a du sens
recharge la page
r
'
è
,
Dans un HCR
:
é
ê
la m
,
me URL
.
si un utilisateur
et il devrait
ê
tre
'
part que n importe quel utilisateur devrait voir en visitant l URL
Les leçons importantes dans tout ça sont
.
:
1.
'é
Toujours stocker l
'
tat utilisateur dans la Session ou dans l URL afin que les utilisateurs
é
ne soient pas d
2.
Stockez chaque
'
'
é
l int
é
rang
é
.
s lors du Hot Code Reload
tat que vous souhaitez mettre en commun entre les utilisateurs à
-
ê
rieur de l URL elle m
me
.
,
Cela conclut notre exploration de Session
'
'
.
une des fonctions les plus utiles de Meteor
N oubliez pas d annuler tous les changements de votre code avant de passer au chapitre
.
suivant
Ajouter des Utilisateurs
é
Depuis le d
,
but
nous avons appris à cr
style particulier et on a tout int
Nous avons m
é
donn
é
paralys
é é
gr
é
é
er et afficher des donn
dans un prototype simple
ê
me vu comment notre UI est r
éé
es ins
6
r
es ou modifi
é
'
.
é ,
active aux changements de donn
é
é
es apparaissent imm
é
par le fait que nous ne pouvons pas ins
pas encore d utilisateurs
es statiques brutes dans un
!
.
diatement
Par contre
é .
rer de donn
es
,
En fait
,
es
et les
notre site est
'
ê
nous n avons m
me
.
Voyons comment corriger ça
Comptes: création d'utilisateurs faciles
,
Dans la plupart des frameworks web
classique
.
,
Bien sur
,
vous devez faire ça dans presque tous les projets
aussi simple que ça le devrait
syst
'
è
.
,
,
Heureusement
ôé
é é
pouvons b
n
'
t
serveur
ficier d un syst
è
(
d
s que vous devez interagir avec OAuth ou un
les choses ont tendance à se compliquer
é .
Meteor a tout pr
contribuer au code c
vu
,
Bootstrap
é
inqui
)
)
JavaScript
,
ôé
et c
'
é é
gr
é
é
velopp
(
,
JavaScript
HTML et CSS
.
),
nous
rence est le style
).
(
meteor
avec
toute notre application avec
ian:accounts-ui-bootstrap-3
,
En ligne de commande
meteor add ian:accounts-ui-bootstrap-3
meteor add accounts-password
Terminal
client
e de Meteor pour les comptes
é
mais comme nous avons d
la seule diff
t
me de compte presque sans effort
nous utiliserons le paquet
tez pas
.
Grâce à la façon dont les paquets Meteor peuvent
Nous pourrions simplement utiliser l UI int
add accounts-ui
'
mais ce n est jamais
, è
De plus
mes d authentification tiers
é
ajouter des comptes utilisateurs est une fonctionnalit
à la place
(
ne vous
nous tapons
:
è
Ces deux commandes nous donnent acc
é
s aux templates sp
pouvons les inclure dans notre site en utilisant le helper
ô
vous pouvez contr
(
align
ôé
ler de quel c
par exemple
t
'
ê
s affiche la fen
'
ciaux des comptes
-ê
te
.
'
tre d authentification en utilisant l attribut
)
-ê
Et comme cet en t
donnons lui un peu de place avec son propre template
)
et nous
{{> loginButtons}} . Une astuce:
{{> loginButtons align="right"}} .
Nous ajouterons les boutons à notre en t
,
(
te commence à grossir
nous le mettrons dans
client/templates/includes/ . Nous utilisons également des balises externes et des classes
é
sp
cifi
é
es par Bootstrap pour nous assurer que tout soit beau
:
<template name="layout">
<div class="container">
{{>header}}
<div id="main">
{{> yield}}
</div>
</div>
</template>
/
/
/
.
client templates application layout html
<template name="header">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="col
lapse" data-target="#navigation">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{pathFor 'postsList'}}">Microscope</a>
</div>
<div class="collapse navbar-collapse" id="navigation">
<ul class="nav navbar-nav navbar-right">
{{> loginButtons}}
</ul>
</div>
</nav>
</template>
/
/
/
.
client templates includes header html
Maintenant
'
,
,
quand nous naviguons dans notre application
nous voyons les boutons
.
d authentification en haut à droite dans le coin du site
Interface intégrée des comptes utilisateur de Meteor
'
'
,
On peut utiliser ça pour s enregistrer
'
,
s authentifier
,
changer son mot de passe
et tout ce
.
qu un simple site comportant des comptes utilisateur a besoin
'
è
Pour indiquer au syst
'
,
un nom d utilisateur
un nouveau fichier
me de compte que nous voulons que les utilisateurs s authentifient avec
nous ajoutons simplement un bloc de configuration
config.js
'
é
à l int
rieur de
client/helpers/ :
Accounts.ui.config({
passwordSignupFields: 'USERNAME_ONLY'
});
/
/
.
client helpers config js
Accounts.ui
dans
Comptes ajout
é
Commit 6-1
é é
s et template int
gr
' -ê
à l en t
te
'
Voir sur GitHub
Lancer l instance
Création de notre premier utilisateur
Enregistrez un compte
:
le bouton
“
”
Sign In
confirme que le compte utilisateur a bien
de ce compte
?
é é
tre acc
tapez
d
.
é é éé
t
cr
pour vous
.
'ù
Mais d o
Ça
é
viennent les donn
es
En ajoutant le paquet
ê
'
changera pour afficher votre nom d utilisateur
e avec
accounts , Meteor a créé une nouvelle collection spéciale, laquelle peut
Meteor.users() . Pour la voir, ouvrez la console de votre navigateur et
:
❯
Meteor.users.findOne();
Console du navigateur
La console retournera un objet correspondant à votre objet utilisateur
è,
plus pr
s
.
vous identifie
é
connect
Notez que vous pouvez
-
é
,
galement r
é
é
cup
'
Si vous regardez de
avec un
_id
-
.
devrait retourner un second utilisateur
Meteor.users.find().count();
Console du navigateur
unique qui
rer l utilisateur actuellement
connectez vous et enregistrez vous avec un compte utilisateur diff
Meteor.user()
1
é
Meteor.user() .
avec
Maintenant d
❯
'
vous pouvez voir que votre nom d utilisateur est dedans
.
,
Mais attendez
é
ex
é
.
rent
cutons
:
La console retourne
é
supprim
'
?
1.
-
Ne devrait il pas y en avoir
2
?
--
Le premier utilisateur a t il
,
SI vous essayez de vous authentifier avec le premier utilisateur
éé
t
vous verrez que ce
.
n est pas le cas
-
é
Assurons nous en et v
é
donn
é
v
es Mongo
rifiera
.
é
rifions dans la zone de stockage des donn
On se connectera à Mongo
:
( meteor mongo
es canonique
,
la base de
)
dans votre terminal
et on
> db.users.count()
2
Console Mongo
.
Il y a bien deux utilisateurs
-
'
Donc pourquoi ne pouvons nous en voir qu un dans le navigateur
?
Une publication mystère !
Si vous repensez au chapitre
nous avons arr
êé
t
'
4,
l envoi des donn
collection des clients connect
'
é autopublish ,
vous pouvez vous souvenir qu on a supprim
é.
s
é
es des collections du serveur vers chaque version local de
Nous avions besoin de cr
é
er un couple publication
é .
souscription afin de faire transiter les donn
'
Mais nous n avons pas encore
pouvons quand m
'
'
tabli de publication utilisateur
é
me voir une donn
e utilisateur
é
La r
es
é
ê
?
é.
s authentifier sur le site
!
'
.
'ù
Donc d o
vient que nous
-
é
ponse est que le paquet comptes auto publie les d
l utilisateur actuellement authentifi
/
tails de base du compte de
S il ne le faisait pas
,
'
l utilisateur ne pourrait pas
'
.
Le paquet comptes publie seulement l utilisateur courant
é
utilisateur ne peut voir les d
'
tails d un autre compte
Ceci explique pourquoi un
.
é
La publication publie donc seulement un objet utilisateur par utilisateur authentifi
(
et aucun
'ê
si vous n
,
De plus
)
é.
tes pas authentifi
les documents ne semblent pas avoir les m
,
Dans Mongo
ê
é .
un utilisateur a beaucoup de donn
Mongo et tapez
.
mes champs sur le serveur et sur le client
es
,
Pour les voir
retournez sur votre terminal
:
> db.users.find()
{
"_id": "H5kKyxtbkLhmPgtqs",
"createdAt": ISODate("2015-02-10T08:26:48.196Z"),
"profile": {},
"services": {
"password": {
"bcrypt": "$2a$10$yGPywo3/53IHsdffdwe766roZviT03YBGltJ0UG"
},
"resume": {
"loginTokens": [{
"when": ISODate("2015-02-10T08:26:48.203Z"),
"hashedToken": "npxGH7Rmkuxcv098wzz+qR0/jHl0EAGWr0D9ZpOw="
}]
}
},
"username": "sacha"
}
Console Mongo
'
Et de l autre c
ô é,
t
'
,
dans le navigateur l objet utilisateur est bien moins rempli
pouvez le voir en tapant la commande
é
quivalente
comme vous
:
Meteor.users.findOne();
Object {_id: "kYdBd9hr3fWPGPcii", username: "tmeasday"}
❯
Console du navigateur
Cet exemple nous montre comment une collection local peut
de la vrai base de donn
é
n
é .
es
'
cessaires à son bon fonctionnement
,
apprendre
é
L utilisateur authentifi
(
,
.
é
tre un sous ensemble s
é
curis
e
voit seulement les informations
dans ce cas
vous vous en apercevrez plus tard
-
ê
'
). '
l authentification
C est un cas utile pour
é
Ça ne veut pas dire que vous ne pourrez rendre publiques des donn
souhaitez
.
éé
Vous pouvez vous r
f
es utilisateur si vous le
rer à la Documentation Meteor pour savoir comment vous
pouvez publier plus de champs dans la collection
Meteor.users .
La Réactivité
6.5
SIDEBAR
Si les collections sont la fonctionnalit
rend utile
é
,
principale de Meteor
é
la R
é
activit
est la coquille qui la
.
Les Collections transforment radicalement la façon dont votre application traite les
modifications de donn
manuellement
(
é .
es
Plut
ô
'
t que d avoir à v
,
par un appel AJAX
par exemple
)
é
é
rifier les modifications de donn
es
,
et de les mettre à jour dans votre page HTML
Meteor applique automatiquement ces modifications à votre interface utilisateur de façon
transparente
.
Prenez un moment pour y penser
:
,
dans les coulisses
'
Meteor est capable de changer toute
-
.
partie de votre interface utilisateur chaque fois qu une collection sous jacente est mise à jour
'
.observe() , une fonction de curseur qui
La meilleure façon de parvenir à cela serait d utiliser
é
d
.
clenche des callbacks lorsque des documents correspondant à ce curseur changent
pourrions alors faire des changements dans le DOM
.
travers ces callbacks
Le code r
é
(
)
le rendu HTML de notre page Web
sultant ressemblerait à quelque chose comme ceci
:
Nous
à
Posts.find().observe({
added: function(post) {
// quand le callback 'added' est déclenché, ajout de l'élément HTML
$('ul').append('<li id="' + post._id + '">' + post.title + '</li>');
},
changed: function(post) {
// quand le callback 'changed' est déclenché, modification du texte de l
'élément HTML
$('ul li#' + post._id).text(post.title);
},
removed: function(post) {
// quand le callback 'removed' est déclenché, suppression de l'élément H
TML
$('ul li#' + post._id).remove();
}
});
é
Vous pouvez probablement d
jà voir comment le code va rapidement se complexifier
.
'
Imaginez comment traiter les modifications de chaque attribut de l article
'
du HTML complexe à l int
é
rieur des
'
<li>
.
de l article
é
qui peuvent survenir quand nous commençons à g
,
et devoir changer
'
Quand
el
-nous utiliser observe() ?
devrions
-
è
Utiliser le mod
'
é
le ci dessus est parfois n
.
s interfacer avec des gadgets tiers
'
d une Collection
,
é
(
,
,
,
é
sp
cialement quand on doit
imaginons que nous voulions ajouter
é
el des marqueurs bas
é
s sur des donn
pour afficher la localisation des utilisateurs authentifi
'
vous aurez besoin d utiliser des callbacks
observe()
é
discuter la carte avec la collection Meteor et savoir comment r
changements de donn
removed
es
)
é .
disons
Dans certains cas
cessaire
Par exemple
ou supprimer sur une carte en temps r
carte
s
rer de multiples sources d information qui
é .
peuvent toutes changer en temps r
é
Sans parler de tous les cas compliqu
é .
es
,
Par exemple
pour appeler les propres m
afin de faire
agir avec les
vous pourriez utiliser les callbacks
é
dropPin()
thodes
et
s
removePin()
added
'
et
de l API
.
Une approche déclarative
Meteor nous fournit un meilleur outil
é
d
.
clarative
'
Être d
:
la r
é
é
é
claratif nous laisse d
é,
qu ils resteront synchronis
s
é,
activit
qui est dans sa structure une approche
finir la relation entre les objets une fois et savoir
é
au lieu de devoir sp
cifier les comportements pour tous les
.
changements potentiels
Ceci est un concept puissant
,
peuvent changer à de façon impr
é
affichons le HTML bas
'
è
parce qu un syst
é
visible
.
é
me temps r
é
En exposant d
é
sur les sources de donn
è
surveiller ces sources et accomplir de mani
'
es r
é
'
el a beaucoup d entr
é
es qui
clarativement la façon dont nous
,
actives que nous observons
Meteor peut
re transparente ce travail de mise à jour
.
permanente de l interface utilisateur
'
é é
Tout ceci pour dire qu au lieu de r
'é
d
crire
:
fl
chir sur des callbacks
observe() , Meteor nous permet
<template name="postsList">
<ul>
{{#each posts}}
<li>{{title}}</li>
{{/each}}
</ul>
</template>
é
Et ensuite r
'
é
cup
rer notre liste d articles avec
:
Template.postsList.helpers({
posts: function() {
return Posts.find();
}
});
è
En arri
-
,
re plan
Meteor d
é
clenche des callbacks
é
sections pertinentes du HTML quand les donn
,
observe()
es r
é
pour nous
é
et red
ssine les
.
actives changent
Surveillance de dépendance dans Meteor: Calculs (Computations)
é , é
Alors que Meteor est un framework temps r
'
application Meteor n est pas r
'
é
.
actif
chaque fois qu il y a un changement
,
de votre code
'
sources de donn
active
é
r
(
,
,
tait le cas
À la place
,
la r
'
é
tout le code à l int
é
é
activit
é
est limit
'
rieur d une
è
votre application enti
é
é
un calcul est un bloc de code qui est ex
é
es r
,
par exemple
active
,
actif
re se rechargerait à
é
e à des zones sp
cifiques
.
,
é
.
r
et nous appellerons ces zones calculs
En d autres termes
r
'é
Si c
el
é
actives dont il d
pend change
)
une variable de Session
.
é
cut
'
à chaque fois qu une des
é
Si vous avez une source de donn
é
et que vous aimeriez r
es
è
agir de mani
re
.
vous aurez besoin de mettre en place un calcul
'
'
é
Notez qu habituellement vous n avez pas besoin de faire ceci parce que Meteor donne d
'
chaque template et helper qu il affiche son propre calcul
û
s
r que vos templates seront r
é
(
ce qui signifie que vous pouvez
é
actifs à afficher leurs donn
).
es sources
jà à
ê
tre
Chaque source de donn
é
é
es r
les laisser savoir quand sa propre valeur change
invalidate()
sur le calcul
,
invalidation
font
é
'
.
Pour ce faire
n
éé
ralement mis en place pour r
,
il appelle la fonction
valuer simplement leurs contenus sur
et c est ce qui arrive aux calculs de template
'
'
.
é é
Les calculs sont g
'
active surveille tous les calculs qui l utilisent pour qu elle puisse
(
bien que les calculs de template
).
galement la magie d essayer et redessiner la page plus efficacement
pouvons avoir plus de contr
'
ô
Bien que nous
,
le sur ce que fait le calcul sur invalidation si vous en avez besoin
.
en pratique c est presque toujours le comportement que vous utiliserez
Mettre en place un Calcul
é
Maintenant que nous comprenons la th
beaucoup plus sens
é.
è
orie derri
re les calculs
é
actif
en mettre un en place semble
Tracker.autorun
Nous pouvons utiliser la fonction
bloc de code dans un calcul et le rendre r
,
pour enfermer un
:
Meteor.startup(function() {
Tracker.autorun(function() {
console.log('There are ' + Posts.find().count() + ' posts');
});
});
'
Tracker
Notez que nous avons besoin d envelopper le bloc
Meteor.startup()
de charger la collection
è
En arri
-
' '
Posts .
, autorun
re plan
que la source de donn
é
cr
é
,
e ensuite un calcul
é
es dont il d
pend change
è
tr
.
é
éé
é
est une source de donn
es r
'
é
'
rieur d un bloc
cutera seulement une fois que Meteor a fini
é
et le d
éé
clenche pour r
valuer à chaque fois
Nous avons mis en place un calcul vraiment
'
s simple qui journalise simplement le nombre d articles à la console
Posts.find()
r
é
pour nous assurer qu il s ex
'
à l int
active
,
.
Maintenant que
il prendra soin de dire au calcul de
valuer à chaque fois que le nombre d articles change
.
> Posts.insert({title: 'New Post'});
There are 4 posts.
é
Le r
é
r
sultat net de tout ceci est que nous pouvons
active de façon tr
è
,
s naturelle
é é
prendra soin de le r
ex
'
é
é
crire du code qui utilise une donn
è
en sachant qu en arri
.
cuter juste au bon moment
-
è
re plan le syst
é
me de d
e
pendance
Créer des Posts
Nous avons vu combien il
à la base de donn
'
é
7
é
é
tait facile de cr
,
,
'
avec l appel
Posts.insert . Mais nous ne pouvons pas attendre de nos utilisateurs
es
qu ils ouvrent la console pour cr
À un moment
er des posts en passant par la console
nous devrons cr
é
.
er un nouveau post
é
er une interface pour permettre à nos utilisateurs de poster de
.
nouvelles histoires sur notre application
Construire la page d'ajout de post
é
Nous commençons par d
finir une route pour notre nouvelle page
:
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() { return Meteor.subscribe('posts'); }
});
Router.route('/', {name: 'postsList'});
Router.route('/posts/:_id', {
name: 'postPage',
data: function() { return Posts.findOne(this.params._id); }
});
Router.route('/submit', {name: 'postSubmit'});
Router.onBeforeAction('dataNotFound', {only: 'postPage'});
/
.
lib router js
Ajouter un lien à l'en-tête
é
Une fois cette route d
-ê
dans notre en t
te
:
,
finie
'
nous pouvons maintenant ajouter un lien à notre page d envoi
<template name="header">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggl
e="collapse" data-target="#navigation">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{pathFor 'postsList'}}">Microscop
e</a>
</div>
<div class="collapse navbar-collapse" id="navigation">
<ul class="nav navbar-nav">
<li><a href="{{pathFor 'postSubmit'}}">Créer un post</a></li
>
</ul>
<ul class="nav navbar-nav navbar-right">
{{> loginButtons}}
</ul>
</div>
</nav>
</template>
/
/
/
.
client templates includes header html
'
Configurer notre route signifie que si un utilisateur se rend à l URL
le template
postSubmit . Écrivons donc ce template :
/submit , Meteor affichera
<template name="postSubmit">
<form class="main form page">
<div class="form-group">
<label class="control-label" for="url">URL</label>
<div class="controls">
<input name="url" id="url" type="text" value="" placeholder="V
otre URL" class="form-control"/>
</div>
</div>
<div class="form-group">
<label class="control-label" for="title">Title</label>
<div class="controls">
<input name="title" id="title" type="text" value="" placeholde
r="Nommez votre article" class="form-control"/>
</div>
</div>
<input type="submit" value="Submit" class="btn btn-primary"/>
</form>
</template>
/
/
/ _
client templates posts post
Note
:
,
ça fait beaucoup de code
.
Bootstrap
Bien que seuls les
é
suppl
.
submit html
mais ça vient simplement du fait que nous utilisons Twitter
éé
l
,
ments de formulaire soient essentiels
.
mentaires aideront à rendre notre appli un peu plus jolie
ressembler à ça
:
les balises
Cela devrait maintenant
Le formulaire de soumission d'article
'
'
.
C est un formulaire simple
puisque nous allons intercepter les
en passant par JavaScript
.
è
é
'
ter de lui ajouter un champ
é é
v
‘
’,
action
é
nements sur le formulaire et mettre à jour les donn
es
Il n y aurait pas de sens à fournir une solution alternative sans
JavaScript quand on consid
est d
é
Nous n avons pas à nous inqui
'
re qu une appli Meteor ne fonctionne plus du tout si JavaScript
é.
sactiv
Créer des posts
'é é
submit (
ô '
Lions un gestionnaire d
'
'é é
d utiliser l
v
nement
'é é
v
nement à l
plut
v
nement
t qu un
submit
é é
v
nement
du formulaire
click
.
Il est pr
éé
f
rable
),
sur le bouton par exemple
'
car cela permettra de prendre en compte toutes les façons possibles d envoyer le formulaire
(
comme appuyer sur entr
é
e par exemple
).
Template.postSubmit.events({
'submit form': function(e) {
e.preventDefault();
var post = {
url: $(e.target).find('[name=url]').val(),
title: $(e.target).find('[name=title]').val()
};
}
});
/
post._id = Posts.insert(post);
Router.go('postPage', post);
/
/ _
client templates posts post
.
submit js
'
Commit 7-1
-
Avec une page d ajout de post et un lien vers celle ci da
Voir sur GitHub
'
Lancer l instance
…
é
Cette fonction utilise jQuery pour v
rifier les valeurs de nos divers champs de formulaire et
construire un nouvel objet post à partir des r
'
preventDefault
sur l argument
'
event
é
.
sultats
de notre gestionnaire pour
'
ê
,
utilis
é
e sur une collection
é .
dans la base de donn
,
correspondante
,
Ainsi
'
es
),
.
.
é
ment dirig
é éé
g
n
r
'
La fonction
'ê
pour l objet qui vient d
id
du Router va utiliser cet
et nous amener sur la bonne page
,
é
’ id
renvoie l
go()
La fonction
un nouveau post est cr
éé
tre ins
'
r
pour construire l URL
.
éé,
l utilisateur envoie le formulaire
instantan
r que le navigateur
nous pouvons router l utilisateur vers la page de son nouveau post
(
insert()
'
û
tre s
n essaie pas de prendre les devants en essayant d envoyer le formulaire
Finalement
'
Nous devons nous assurer d utiliser
'
et l utilisateur est
.
vers la page de discussion de ce nouveau post
Ajouter un peu de sécurité
é
Cr
er des posts est tr
ils doivent
ê
è
s bien
tre authentifi
'
,
'
mais nous ne voulons pas laisser n importe quel visiteur le faire
é
.
s pour pouvoir poster
û,
Bien s
r
nous pouvons commencer en
é.
cachant la page d ajout de post pour les utilisateurs non authentifi
pourrait cr
é
:
ê
er un post depuis la console du navigateur sans
s
Cependant un utilisateur
é,
tre authentifi
et nous ne
.
pouvons pas nous le permettre
é
Heureusement la s
é
d
é
sactiv
é
e par d
curit
é
des donn
é
.
es est incluse dans les collections Meteor
faut lorsque vous cr
é
.
ez un nouveau projet
Elle est
Cela vous permet de commencer
é
facilement à cr
.
er votre application tout en laissant les trucs ennuyeux pour plus tard
'
,
Notre appli n a plus besoin de ces petites roues
insecure :
- !
alors enlevons les
Supprimons le paquet
meteor remove insecure
Terminal
è
Apr
s avoir fait ça
,
.
vous remarquerez que le formulaire de post ne fonctionne plus
'
C est parce
que sans le paquet
insecure , les insert() côté client sur la collection des posts
ne sont plus
é.
autoris
s
Nous devons soit donner quelques r
é
autoris
é
à ins
rer un post
,
è
é
gles explicites à Meteor pour d
ôé
soit faire nos insertions c
t
finir quand un client est
.
serveur
Autoriser les insertions de post
,
Pour commencer
que notre formulaire fonctionne à nouveau
é
technique diff
ôé
nous allons voir comment autoriser les insertions de post c
rente
,
,
mais pour le moment
fonctionnent à nouveau
'
.
Il s av
è
t
client pour
re que nous finirons par adopter une
le simple code suivant permettra que les choses
:
Posts = new Meteor.Collection('posts');
Posts.allow({
insert: function(userId, doc) {
// autoriser les posts seulement si l'utilisateur est authentifié
return !! userId;
}
});
/
.
collections posts js
Commit 7-2
Sans Insecure et avec des r
Voir sur GitHub
é
dans lesquelles les clients sont autoris
,
Le
nous disons
userId
gles de modifications sur les
'
“
é
é
de l utilisateur proc
'
“
ceci est un ensemble de circonstances
s à faire des choses à la collection
les clients peuvent ins
…
Lancer l instance
Posts.allow , qui dit à Meteor que
Nous appelons
cas
è
'
rer des posts du moment qu ils ont un
dant à la modification est pass
é
”
Post . Dans notre
”
userId .
lors des appels à
allow
et
(
deny
ou renvoie
'
null
'
é
Et comme les comptes utilisateurs sont li
userId
pour
é
Nous avons r
ê
.
ce qui est presque toujours utile
s au noyau de Meteor
,
nous pouvons compter sur
.
tre toujours fiable
'
ussi à nous assurer que l on doit
é
vous d
)
é,
si l utilisateur n est pas authentifi
é
connecter et de cr
er un post
;
ê
é
tre authentifi
pour cr
é
.
er un post
vous devriez voir ceci dans votre console
Essayez de
:
Échec de l'insertion : Accès refusé
,
Cependant
è
nous avons encore à nous occuper de quelques probl
é
Les utilisateurs non authentifi
mes
:
é
s peuvent toujours acc
é
der au formulaire de cr
ation de
.
post
'
é
Le post n est pas li
ôé
c
t
'
'
à l utilisateur de quelque façon que ce soit
Plusieurs posts peuvent
é
R
).
serveur pour s occuper de ça
è
solvons ces probl
ê
éé
tre cr
ê
s pointant vers la m
.
mes
Sécuriser l'accès au nouveau formulaire
.
me URL
(
'
et il n y a pas de code
Commençons par
'
é
è
viter l acc
é
s des utilisateurs non authentifi
Nous le ferons au niveau du routeur
Un hook
'
(“
crochet
”
)
en français
.
l action prise par le routeur
,
é
en d
é
accessDenied
'
).
d autre à faire
.
intercepte le processus de routage et change potentiellement
'
Vous pouvez l imaginer comme un garde de s
(
'
'
é,
postSubmit
attendu
. :
(
)
é
,
puis nous stoppons le routeur ici
Modifions donc router js
Router.route('/posts/:_id', {
name: 'postPage',
data: function() { return Posts.findOne(this.params._id); }
});
Router.route('/submit', {name: 'postSubmit'});
var requireLogin = function() {
if (! Meteor.user()) {
this.render('accessDenied');
} else {
this.next();
}
}
Router.onBeforeAction('dataNotFound', {only: 'postPage'});
Router.onBeforeAction(requireLogin, {only: 'postSubmit'});
.
lib router js
é
ons aussi le template pour la page
'
è
acc
s refus
’
é
rifie
et sinon afficher le template
Router.route('/', {name: 'postsList'});
Nous cr
qui v
s
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() { return Meteor.subscribe('posts'); }
});
/
é
curit
è .
ou de vous refuser l acc
rifier si l utilisateur est authentifi
au lieu du
.
finissant un route hook
vos identifiants avant de vous laisser entrer
Nous avons besoin de v
'
s au formulaire d ajout de post
é , accessDenied :
'
il n a rien
<template name="accessDenied">
<div class="access-denied page jumbotron">
<h2>Accès refusé</h2>
<p>Vous ne pouvez pas accéder à cette page ! Veuillez vous connecter
.</p>
</div>
</template>
/
/
/
_
client templates includes access
.
denied html
'
è
Acc
Commit 7-3
é
s à la page d ajout de post refus
'
Voir sur GitHub
Maintenant
voir ceci
,
si vous allez à http
//
:
:
Lancer l instance
/
:3000
localhost
…
lorsque non authen
/
submit
sans
ê
é,
tre authentifi
vous devriez
Le template d'accès refusé
,
Ce qui est pratique à propos des hooks de routage
'
'
é
c est qu ils sont eux aussi r
.
actifs
' --
C est à
'
'
'
dire que nous n avons pas besoin de penser à des callbacks quand l utilisateur s authentifie
'é
quand l
'
'
tat d authentification de l utilisateur change
é
change instantan
'
é
d explicite pour le g
-
,
Authentifiez vous
accessDenied
'
accessDenied
ment de
rer
(
à
'
,
postSubmit
é
î
.
puis essayer de rafra chir la page
s afficher bri
)
Pour
existe r
é
é
è
me
(
é
authentifi
è
Apr
,
s tout
é
é
crire
-ê
'
tre parfois le template
è
é é
rifi
.
'
si l utilisateur actuel
s que possible
(
é
stock
,
ê
avant m
é
dans la m
.
La raison
'
me qu il ait
moire locale du
'
qui est courant et que vous rencontrerez d autant plus que vous allez
é
vous pencher sur les subtilit
afficher un
).
vement avant que la page d ajout de post apparaisse
ellement
viter ce probl
sans que nous ayons rien à
Vous verrez peut
è
avec le serveur est v
navigateur
par le routeur
et cela fonctionne d ailleurs pour tous les onglets
en est que Meteor commence à afficher les templates d
convers
é
le template utilis
:
s de latence entre client et serveur
),
nous allons simplement
'
cran de chargement pendant que nous attendons de savoir si l utilisateur est
.
ou pas
'
à cet instant nous ne savons pas si l utilisateur a les identifiants corrects
ne pouvons afficher aucun des templates
accessDenied
ou
postSubmit
,
et nous
Nous modifions donc notre hook pour utiliser notre template de chargement pendant que
Meteor.loggingIn()
est vrai
:
//...
var requireLogin = function() {
if (! Meteor.user()) {
if (Meteor.loggingIn()) {
this.render(this.loadingTemplate);
} else {
this.render('accessDenied');
}
} else {
this.next();
}
}
Router.onBeforeAction('dataNotFound', {only: 'postPage'});
Router.onBeforeAction(requireLogin, {only: 'postSubmit'});
.
avant de le savoir
/
.
lib router js
Afficher un
Commit 7-4
é
'
.
cran de chargement pendant l authentification
'
Voir sur GitHub
Lancer l instance
Cacher le lien
'é
La façon la plus simple d
'
'
'
viter aux utilisateurs d essayer d atteindre cette page par erreur
lorsqu ils ne sont pas connect
é
.
s est de leur cacher le lien
Nous pouvons faire cela facilement
//...
<ul class="nav navbar-nav">
{{#if currentUser}}<li><a href="{{pathFor 'postSubmit'}}">Créer un post<
/a></li>{{/if}}
</ul>
//...
/
/
/
.
client templates includes header html
'
Commit 7-5
é.
Afficher le lien d ajout de post seulement si authentifi
Voir sur GitHub
Le helper
currentUser
est fourni par le paquet
'
'
Lancer l instance
accounts
'é
et est l
quivalent Spacebars de
Meteor.user() . Puisqu il est réactif, le lien apparaîtra ou disparaîtra selon que vous vous
é
connectez ou d
'
.
connectez de l application
:
Meteor Method : une meilleure abstraction et sécurité
Nous avons r
é,
authentifi
s
é
é
ussi à s
'
é
et
'
'
è
curiser l acc
s à la page d ajout de post pour les utilisateurs non
viter qu ils puissent cr
é
ê
er des posts m
Nous avons cependant encore plusieurs choses à faire
'
.
me s ils trichent en utilisant la console
:
Marquer la date du post avec un timestamp
'
ê
S assurer que la m
Ajouter des d
me URL ne peut pas
ê
é
tre post
'
é
(
tails à propos de l auteur du post
'
'
e plus d une fois
,
ID
nom d utilisateur
,
)
.
etc
Vous pourriez penser que nous pouvons faire tout cela dans notre gestionnaire de l
submit . Cependant, en réalité, nous arriverions vite à plusieurs problèmes :
'é é
v
nement
,
Pour le timestamp
'
,
l utilisateur
Le c
ôé
t
é
nous aurions à esp
'
'
rer que l heure soit correcte sur l ordinateur de
ce qui ne sera pas toujours le cas
é
client ne sera pas au courant de toutes les URL post
'
seulement les posts que l utilisateur peut actuellement voir
). '
comment ceci fonctionne exactement
URL du c
ôé
t
client
.
, ê
Enfin
m
es sur le site
(
nous verrons plus tard
'
é
,
par des gens utilisant la console
,
Pour toutes ces raisons
ôé
tails utilisateurs c
t
é
,
client
des
nous ne nous
.
'é é
il vaut mieux garder nos gestionnaires d
v
nements simples
,
é
'
ce qui pourrait exposer notre appli à une exploitation
nous faisons plus que les insertions et mises à jour les plus basiques
M
î
Il conna tra
Il n y a donc pas de moyen d assurer l unicit
me si nous pourrions ajouter les d
assurerions pas de leur exactitude
.
.
Et si
ô
utilisons plut
t une
.
thode
é
Une M
ôé
thode Meteor est une fonction c
sont pas totalement
remove
de
Revenons à
é
è
trang
Collection
res
–
t
,
en fait
é
serveur qui est appel
,
en coulisses
é
sont toutes des M
.
thodes
ôé
e c
les fonctions
t
.
client
insert , update , et
é
Voyons comment cr
'
Elles ne nous
ô
er la n
.
tre
post_submit.js . Plutôt que d insérer directement dans la collection Posts ,
nous allons appeler une M
é
é postInsert :
thode nomm
e
Template.postSubmit.events({
'submit form': function(e) {
e.preventDefault();
var post = {
url: $(e.target).find('[name=url]').val(),
title: $(e.target).find('[name=title]').val()
};
Meteor.call('postInsert', post, function(error, result) {
// affiche l'erreur à l'utilisateur et s'interrompt
if (error)
return alert(error.reason);
});
}
});
Router.go('postPage', {_id: result._id});
/
/
/ _
client templates posts post
Meteor.call
La fonction
.
submit js
appelle une Methode nomm
'
pouvez fournir des arguments pour l appel
,
finalement y attacher un callback
( ,'
ici
l objet
é
qui sera execut
é
.
e par son premier argument
post
Vous
),
construit depuis le formulaire
ôé
quand la Methode c
t
et
serveur sera
é.
termin
Les callbacks des m
é
une raison ou une autre
return
'
, error
thodes meteor ont toujours deux arguments
,
'
l argument
error
pour interrompre le callback
).
,
existe
'
et
result . Si pour
nous alerterons l utilisateur
,
Si tout fonctionne normalement
î
l utilisateur vers la page de discussion du post fra chement cr
(
en utilisant
nous redirigerons
éé .
e
Test de sécurité
é
Nous allons profiter de cette opportunit
utilisant le paquet
é
pour s
curiser notre m
é
thode un peu plus en
audit-argument-checks .
'
é
Ce paquet vous permet de tester n importe quel objet JavaScript selon un sch
,
Dans notre cas
é
authentifi
(
'
'
nous l utiliserons pour tester que l utilisateur qui utilise la m
en nous assurant que
Meteor.userId()
î
est une cha ne
é
é é
ma pr
d
.
fini
thode est bien
( String ),
'
et que l objet
postAttributes
é
pass
'
é
en tant qu argument à la m
î
thode contient les cha nes
title
et
url , pour ne pas nous retrouver à entrer des morceaux aléatoires de données dans notre
é .
base de donn
es
é
D
finissons donc la m
’
é é : _id
soumis
postInsert
de
dans notre fichier
posts.js
t
s
l
é
tendre
et le nom
( submitted ),
( '
final au client
puisque de toute façon les m
( extend ) ' postAttributes
( username ) '
,
'
' é
,
'
'
de l utilisateur
avant d ins
en d autres mots
.
l objet
thodes Meteor les
Meteor.methods({
postInsert: function(postAttributes) {
check(Meteor.userId(), String);
check(postAttributes, {
title: String,
url: String
});
var user = Meteor.user();
var post = _.extend(postAttributes, {
userId: user._id,
author: user.username,
submitted: new Date()
});
var postId = Posts.insert(post);
}
return {
_id: postId
};
/
.
lib collections posts js
ainsi que l horodatage du post
é
é
celui à l origine de l appel de cette m
Posts = new Mongo.Collection('posts');
/
é
avec trois nouvelles
rer le tout dans notre base de donn
JavaScript
});
collections/posts.js . Nous
.
Nous allons ensuite
propri
thode
allow()
supprimerons le bloc
ignorent
é
’ _id
e et de retourner l
thode
)
dans un objet
é
Notez que la m
_.extend()
thode
permet simplement d
’“é
”
tendre
,
fait partie de la librairie Underscore
éé
un objet avec les propri
t
'
s d un autre
.
Commit 7-6
é
En utilisant une m
'
et qu elle vous
.
thode pour soumettre le post
Voir sur GitHub
'
Lancer l instance
Bye Bye Allow/Deny
é
Les m
.
confiance
/
é
thodes Meteor sont ex
'
cut
es sur le serveur
,
et donc Meteor leur fait
'
é
C est pourquoi les m
.
é
thodes Meteor ignorent n importe quel callback
allow deny
é
Si vous voulez ex
,
sur le serveur
cuter du code avant chaque
é
nous vous sugg
rons de jeter un
insert , update , ou remove
ê
-
m
œ
me
.
il au paquet collection hooks
Éviter les doublons
'
Nous ferons un dernier test avant d int
é é éé
t
cr
,
auparavant
'
'
é
é
grer notre m
thode
.
Si un post avec la m
,
nous n ajouterons pas le lien une nouvelle fois
allons rediriger l utilisateur vers ce post
.
ê
é
me url a d
jà
mais au lieu de cela nous
Meteor.methods({
postInsert: function(postAttributes) {
check(this.userId, String);
check(postAttributes, {
title: String,
url: String
});
var postWithSameLink = Posts.findOne({url: postAttributes.url});
if (postWithSameLink) {
return {
postExists: true,
_id: postWithSameLink._id
}
}
var user = Meteor.user();
var post = _.extend(postAttributes, {
userId: user._id,
author: user.username,
submitted: new Date()
});
var postId = Posts.insert(post);
});
return {
_id: postId
};
}
/
/
.
lib collections posts js
é
Nous cherchons dans notre base de donn
,
un
nous retournons
( return ) ’ _id
l
es un post avec la m
ex
é
é
cuter la d
é
clenchons un appel à
me url
'é é
v
pour
è .
re
'
return , la méthode s interrompt à ce moment sans
insert , évitant ainsi avec élégance de créer des doublons.
claration
ôé
nement c
Si nous en trouvons
t
'
Tout ce qui nous reste à faire est d utiliser cette nouvelle information
helper d
.
é é postExists:true
de ce posts avec la propri
informer le client de ce cette situation particuli
Et puisque nous d
ê
t
'
postExists
client pour afficher un message d avertissement
:
dans notre
Template.postSubmit.events({
'submit form': function(e) {
e.preventDefault();
var post = {
url: $(e.target).find('[name=url]').val(),
title: $(e.target).find('[name=title]').val()
};
Meteor.call('postInsert', post, function(error, result) {
// affiche l'erreur à l'utilisateur et s'interrompt
if (error)
return alert(error.reason);
// affiche ce résultat mais route tout de même
if (result.postExists)
alert('Ce lien a déjà été utilisé');
});
Router.go('postPage', {_id: result._id});
}
});
/
/
/ _
client templates posts post
.
submit js
Commit 7-7
'
'
é
S assurer de l unicit
Voir sur GitHub
'
.
de l url du post
'
Lancer l instance
Trier les posts
é
Maintenant que nous avons une date de cr
'
'
é
s assurer qu ils soient class
'
é
utiliser l op
rateur
,
ation sur tous nos posts
sort
.
s en fonction de cet attribut
,
de Mongo
et un signe indiquant si le tri doit
ê
Pour cela
é
qui attend un objet constitu
é
tre croissant ou d
.
croissant
,
il semble bienvenu de
nous pouvons simplement
é
des cl
s par lesquelles trier
Template.postsList.helpers({
posts: function() {
return Posts.find({}, {sort: {submitted: -1}});
}
});
/
/
/
_
client templates posts posts
.
list js
Commit 7-8
é
Tri des posts par date de cr
'
Voir sur GitHub
é
Ça a demand
'
,
un peu de travail
Lancer l instance
mais nous avons maintenant une interface utilisateur qui
é
permet d ajouter du contenu de façon s
é
curis
e à notre appli
é
é
de le modifier ou de le supprimer
.
!
Mais toute application qui permet à ses utilisateurs de cr
la possibilit
.
ation
er du contenu doit aussi leur donner
Ce sera le sujet du prochain chapitre
.
La Compensation de Latence
,
Dans le dernier chapitre
é
M
nous avons pr
é
é
sent
7.5
SIDEBAR
un nouveau concept du monde Meteor
:
les
.
thodes
Sans compensation de latence
é
Une M
'
thode Meteor est un moyen d ex
é .
façon structur
e
,
Dans notre exemple
é
é
cuter une s
é
nous avons utilis
é
assurer que les nouveaux articles seraient tagu
'
l heure du serveur
,
Cependant
è
probl
.
é
valeurs al
é
si Meteor ex
Consid
é
une M
thode car nous voulions nous
'
s avec le nom et l id de leur auteur ainsi que
.
é
me
'
rie de commandes sur le serveur d une
,
cute des Methodes dans sa plus simple façon
é
rez la s
’é é
quence suivante d
'
v
nements
atoires choisies seulement pour l exemple
):
(
note
:
nous aurions un
les horodatages sont des
+0 : '
+200 :
+500 :
ms
L utilisateur clique sur un bouton et le navigateur renvoie un appel de M
é
ms
Le serveur fait des changements dans la base de donn
ms
Le client reçoit ces changements
é
Si Meteor op
'
,
rait de cette façon
é
actions et l affichage des r
é
proximit
moderne
).
avec le serveur
!
,
'
é
sultats
(
é
ce d
calage
calage entre la r
é
.
alisation de ces
é
tant plus ou moins visible selon votre
Nous ne pouvons nous le permettre dans une application web
Compensation de latence
.
thode
es Mongo
met à jour l interface utilisateur
il y aurait alors un petit d
é
Avec compensation de latence
Pour
é
è
viter ce probl
é
Quand nous avons d
é
dans le r
–
pertoire
'
,
me
é
finit notre M
'
'
'
'
!
collections/ . Ceci signifie qu elle est disponible pour le serveur
cutera sur les deux en m
Quand nous faisons un appel de M
é
ê
me temps
thode
.
Compensation de latence
post , nous l avons placée à l intérieur d un fichier
thode
é
et elle s ex
é
Meteor introduit un concept appel
,
et le client
'
le client envoie l appel au serveur
,
mais simule
é
galement simultan
workflow devient
+0
+0
:
ms
:
ms
'
é
é
ment l action de la M
:
'
ôé
thode sur ses collections c
'
'
é
Le client simule l action de l appel de M
'
é
Notre
ms
ms
:
:
ôé
thode sur les collections c
t
é
é
'
é
(
é é
qui sont g
n
.
ê
ralement les m
,
é,
s
en les
mes
.
).
ter ceci
é
sultat pour l utilisateur est de voir les changements instantan
serveur revient un peu plus tard
client et
es Mongo
Le client reçoit ces changements et annule ses changements simul
'
.
thode
.
Le serveur fait les changements dans la base de donn
L interface utilisateur change pour refl
é
ter ceci
remplaçant par les changements du serveur
Le r
client
L utilisateur clique sur un bouton et le navigateur renvoie un appel de M
met à jour l interface utilisateur pour refl
+200
+500
.
t
il peut y avoir
(
)
ou non
.
que les documents canoniques du serveur arrivent
.
ment
Quand la r
é
ponse du
des changements visibles à mesure
Une chose à retenir est donc que nous
devons nous assurer que nous simulons les documents aussi proches de la r
é
é
alit
que
.
possible
Observer une compensation de latence
'
Nous pouvons faire un petit changement à l appel de la m
.
action
,
Pour ce faire
'
thode
nous utiliserons la fonction bien pratique
retarder l appel de la m
.
é
é
thode de
5
,
secondes
mais
('
post
pour voir cela en
Meteor._sleepForMs()
c est un point crucial
)
pour
seulement sur le
serveur
Nous utiliserons
sur le client
é
M
(
isServer
comme une
thode que Meteor ex
'
“é
”)
bauche
é
.
ou sur le serveur
cute sur le client en parall
é
cours d ex
é
pour demander à Meteor si la M
è ,
le
Une
é
,
caract
pendant que la
.
'
caract
re
è
re
“
vraie
”
é
M
thode est en
cution sur le serveur
nous allons retarder l avancement des choses de
è
'
e
bauche est la simulation d une
'
é
Nous allons donc demander à Meteor si le code est en cours d ex
le cas
é
thode est actuellement invoqu
(server)
à la fin du titre de notre article
(client) :
.
5
cution sur le serveur
.
î
secondes et ajouter la cha ne de
,
Sinon
î
'
Si c est
nous ajouterons la cha ne de
Posts = new Mongo.Collection('posts');
Meteor.methods({
postInsert: function(postAttributes) {
check(this.userId, String);
check(postAttributes, {
title: String,
url: String
});
if (Meteor.isServer) {
postAttributes.title += postAttributes.title + "(server)";
// attente de 5 secondes
Meteor._sleepForMs(5000);
} else {
postAttributes.title += "(client)";
}
var postWithSameLink = Posts.findOne({url: postAttributes.url});
if (postWithSameLink) {
return {
postExists: true,
_id: postWithSameLink._id
}
}
var user = Meteor.user();
var post = _.extend(postAttributes, {
userId: user._id,
author: user.username,
submitted: new Date()
});
var postId = Posts.insert(post);
});
return {
_id: postId
};
}
/
.
collections posts js
Si nous nous arr
ê
,
tions ici
é
la d
monstration ne serait pas concluante
'
.
on dirait que le formulaire de soumission d article se met en pause pendant
,
de rediriger vers la liste des posts principaux
'
'é
Dans l
5
,
tat des choses
secondes avant
et pas grand chose d autre se passe
.
,
Pour comprendre cela
revenons au manager de l
'é é
v
nement de soumission de post
:
Template.postSubmit.events({
'submit form': function(e) {
e.preventDefault();
var post = {
url: $(e.target).find('[name=url]').val(),
title: $(e.target).find('[name=title]').val()
};
Meteor.call('postInsert', post, function(error, result) {
// affiche l'erreur à l'utilisateur et s'interrompt
if (error)
return alert(error.reason);
// affiche ce résultat mais 'route' tout de même
if (result.postExists)
alert('This link has already been posted');
});
Router.go('postPage', {_id: result._id});
});
}
/
/
/ _
client templates posts post
é
Nous avons plac
é
la m
.
thode
rediriger
'
.
submit js
notre appel de routeur
'
Router.go()
é
à l int
'
rieur du callback de l appel de
Ce qui signifie que le formulaire attend que cette m
é
thode r
é
ussisse avant de
.
C est normalement la bonne mani
'
è
.
re de faire les choses
Apr
è
,
s tout
vous ne pouvez pas
,
rediriger l utilisateur avant de savoir si la soumission de son post est valide ou pas
ê
ce serait extr
é
mement d
,
une nouvelle fois
è ,
en arri
'ê
routant d
re
é
tre redirig
è
une premi
'ê
re fois et ensuite d
parce que
é
tre redirig
é ,
vers la page de soumission de post pour corriger vos donn
es
.
tout cela en quelques secondes
,
Mais pour le bien de cet exemple
é
imm
diatement
postsList
(
.
Ainsi
,
nous voulons voir les r
'
é
sultats de nos actions
nous allons changer l appel du routeur pour rediriger vers la route
nous ne pouvons pas diriger vers le post car nous ne connaissons pas son
_id
),
é
en dehors de la m
'
thode
,
pour ensuite l extraire du callback
et voir ce qui se passe
:
Template.postSubmit.events({
'submit form': function(event) {
event.preventDefault();
var post = {
url: $(e.target).find('[name=url]').val(),
title: $(e.target).find('[name=title]').val()
};
Meteor.call('postInsert', post, function(error, result) {
// affiche l'erreur à l'utilisateur et s'interrompt
if (error)
return alert(error.reason);
// affiche se résultat mais 'route' tout de même
if (result.postExists)
alert('This link has already been posted');
});
Router.go('postsList');
}
});
/
/
/ _
client templates posts post
D
.
submit js
'
Commit 7-5-1
é
'
Voir sur GitHub
é
Si nous cr
.
action
ons un article maintenant
è
Premi
dans la liste
,
rement
é
reli
…
monstration de l ordre d apparition des articles en uti
,
,
nous verrons clairement la compensation de latence en
éé
un article est ins
):
à Github
'
Lancer l instance
r
avec
(client)
dans le titre
(
le premier article
Notre article comme initialement stocké dans la collection côté client
,
Ensuite
éé
ins
r
,
cinq secondes plus tard
par le serveur
é
il est proprement remplac
avec le vrai document qui a
:
Notre article une fois que le client reçoit la mise à jour de la collection côté serveur
Méthodes des collections sur le client
éé
t
é
Vous pourriez penser que les M
ê
ô
tre plut
.
t simples
,
En fait
mutation de collection
é
Quand vous d
é
train de d
,
mots
é
thodes sont compliqu
é
nous avons d
, insert , update
é
jà vu trois m
et
é
thodes
quand vous appelez
s cela
è
thodes tr
é 'posts' ,
e
: posts/insert , posts/update
Posts.insert()
,
mais en fait elles peuvent
s simples
vous
:
é
les M
thodes de
et
ê
tes implicitement en
,
thode de compensation de latence qui fait deux choses
'
posts/delete . En d autres
sur votre collection client
é
M
è
remove .
finissez une collection serveur appel
finir trois M
es apr
vous appelez une
:
1.
é
Des v
deny
rifications pour voir si vous faites la mutation en appelant des callbacks
2.
(
'
cependant il n est pas n
).
é
allow
et
cessaire que cela arrive dans la simulation
é
La modification vers le stockage de donn
-
.
es sous jacent
Des méthodes qui appellent des Méthodes
Si vous suivez bien
é
une autre M
,
thode
-ê
( posts/insert )
vous venez peut
Quand la simulation
é
tre juste de r
é
quand nous ins
(
ôé
version c
'
effectuons la simulation d un
t
insert
(
'
t
serveur
)
thode
.
'
post
appelle
Comment ça marche
é
est en cours d ex
,
cution
nous
rons donc dans notre collection cliente
,
?
ôé
nous attendons que la version c
t
),
mais
serveur
.
post
le fasse
é
Par cons
'
c
é
rons notre article
thode
é
nous ins
, insert ô é
quent
,
quand la M
é
s inqui
é
client de la M
nous ne faisons pas le vrai
de
aliser que notre M
ter de la simulation
N oubliez pas comme pr
é
,
post côté serveur appelle insert
thode
'
et l insertion continue sans encombre
éé
c
.
'
il n y a pas besoin de
é
demment de supprimer les changements effectu
chapitre avant de passer au suivant
.
s au cours de ce
Editer des Posts
8
é
Maintenant que nous pouvons cr
.
et les supprimer
'
la prochaine
Puisque l interface est simple à mettre en
è
voir comment Meteor g
'
,
er des posts
é
tape est de pouvoir les modifier
œ
uvre
.
,
'
é
c est le moment id
al de
re les permissions des utilisateurs
.
Voyons d abord le router
'
é
Nous lui ajoutons une route afin d acc
é :
des posts et lui donnons des donn
es
der à la page de modification
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() { return Meteor.subscribe('posts'); }
});
Router.route('/', {name: 'postsList'});
Router.route('/posts/:_id', {
name: 'postPage',
data: function() { return Posts.findOne(this.params._id); }
});
Router.route('/posts/:_id/edit', {
name: 'postEdit',
data: function() { return Posts.findOne(this.params._id); }
});
Router.route('/submit', {name: 'postSubmit'});
var requireLogin = function() {
if (! Meteor.user()) {
if (Meteor.loggingIn()) {
this.render(this.loadingTemplate);
} else {
this.render('accessDenied');
}
} else {
this.next();
}
}
Router.onBeforeAction('dataNotFound', {only: 'postPage'});
Router.onBeforeAction(requireLogin, {only: 'postSubmit'});
/
.
lib router js
La template de modification des posts
Concentrons nous maintenant sur la template
.
Notre template
postEdit
reste tr
è
s classique
:
<template name="postEdit">
<form class="main form page">
<div class="form-group">
<label class="control-label" for="url">URL</label>
<div class="controls">
<input name="url" id="url" type="text" value="{{url}}" placeholder
="Votre URL" class="form-control"/>
</div>
</div>
<div class="form-group">
<label class="control-label" for="title">Title</label>
<div class="controls">
<input name="title" id="title" type="text" value="{{title}}" placeho
lder="Nommez votre post" class="form-control"/>
</div>
</div>
<input type="submit" value="Submit" class="btn btn-primary submit"/>
<hr/>
<a class="btn btn-danger delete" href="#">Supprimer le post</a>
</form>
</template>
/
/
/ _
client templates posts post
Et voilà le fichier
.
edit html
post_edit.js
qui va avec
:
Template.postEdit.events({
'submit form': function(e) {
e.preventDefault();
var currentPostId = this._id;
var postProperties = {
url: $(e.target).find('[name=url]').val(),
title: $(e.target).find('[name=title]').val()
}
Posts.update(currentPostId, {$set: postProperties}, function(error) {
if (error) {
// affiche l'erreur à l'utilisateur
alert(error.reason);
} else {
Router.go('postPage', {_id: currentPostId});
}
});
},
'click .delete': function(e) {
e.preventDefault();
if (confirm("Delete this post?")) {
var currentPostId = this._id;
Posts.remove(currentPostId);
Router.go('postsList');
}
}
});
/
/
/ _
client templates posts post
.
edit js
Normalement la majeure partie de ce code devrait vous
Deux
é é
v
nements sont pr
'
é
'é é
formulaire et l autre pour l
'é é
L
v
v
nement
è
nement de suppression est tr
é
d
sents dans notre template
click
s simple
'
:
'
.
é
.
sent
'é é
l un pour l
v
submit
nement
du
.
du lien de suppression du post
ê
on emp
post actuel depuis les informations de la template
'
tre familier à pr
'
:
faut et on demande une confirmation à l utilisateur
l utilisateur sur l accueil
ê
,
'
che l activation des
.
'
é é
v
,
Enfin si on l obtient
nements par
on r
é
è
cup
on supprime le post et on redirige
'
re l ID du
'é é
L
v
,
nement de mise à jour du post est un peu plus long
,
avoir
,
une fois de plus
du formulaire
)
et r
é
ê é
emp
cup
éé
r
'
ch
'
l activation des
é,
l ID du post concern
'
$set
é
(
é
nements classiques
on r
é
è
cup
(
è
s
lors de la soumission
re les valeurs du formulaire depuis
Collection.update()
'
)
'
é
de Meteor avec l op
rateur
et utilisons un callback pour afficher une erreur
é
chec ou renvoie l utilisateur sur le post concern
è.
succ
thode
qui remplace un ensemble de champs
si la mise à jour est un
v
Apr
postProperties .
la page et on les sauvegarde dans l objet
Nous passons alors cet objet à la m
é é
é.
mais pas plus compliqu
si la mise à jour est un
s
Ajouter des liens
Nous devons bien
leurs posts
é
videmment rajouter un lien pour que les utilisateurs puissent modifier
:
<template name="postItem">
<div class="post">
<div class="post-content">
<h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
<p>
submitted by {{author}}
{{#if ownPost}}<a href="{{pathFor 'postEdit'}}">Edit</a>{{/if}}
</p>
</div>
<a href="{{pathFor 'postPage'}}" class="discuss btn btn-default">Discute
r</a>
</div>
</template>
/
/
/ _
client templates posts post
,
De plus
.
item html
'
.
nous ne devons pas afficher ce lien à n importe qui
rajoutons un helper
ownPost :
'
C est pour cela que nous
Template.postItem.helpers({
ownPost: function() {
return this.userId === Meteor.userId();
},
domain: function() {
var a = document.createElement('a');
a.href = this.url;
return a.hostname;
}
});
/
/
/ _
client templates posts post
.
item js
Formulaire d'édition
Commit 8-1
'é
Ajout des formulaire d
Voir sur GitHub
'
Lancer l instance
,
Notre formulaire pour modifier les posts parait correct
.
modifier tout de suite
-- ?
Que se passe t il
.
dition
pourtant vous ne pourrez pas les
Mettre en place les permissions
é
Depuis que nous avons supprim
é
provenant du client sont cat
Pour r
é
fichier
,
gler cela
insecure , toutes les requêtes de modifications
é .
goriquement refus
es
.
nous devons fixer des permissions
permissions.js
dans le dossier
é
seront charg
le paquet
es en premier
(
, é
Pour commencer
cr
ez un nouveau
lib . Nous serons ainsi sûr que nos permissions
):
et disponible dans les deux environnements
// check that the userId specified owns the documents
ownsDocument = function(userId, doc) {
return doc && doc.userId === userId;
}
/
.
lib permissions js
é
Dans le chapitre Cr
,
er des Posts
é
ins
é
rions les nouveaux posts via des m
Mais maintenant que nous
le fichier
'
posts.js
é
nous n avions pas utilis
ôé
thodes c
t
la m
serveur
(
é
thode
allow()
qui passent outre
é
,
ditons et supprimons des posts depuis le client
et rajoutons la fameuse m
é
thode
car nous
retournons dans
allow() :
Posts = new Mongo.Collection('posts');
Posts.allow({
update: function(userId, post) { return ownsDocument(userId, post); },
remove: function(userId, post) { return ownsDocument(userId, post); },
});
//...
/
/
.
lib collections posts js
)
allow() .
Commit 8-2
Ajout de permissions basiques pour v
é
é
rifier le propri
…
tai
'
Voir sur GitHub
Lancer l instance
Limiter les éditions
'
Ce n est pas parce que vous pouvez
'é
'
d
diter toutes les propri
éé.
t
' '
s
é
ê
diter vos propres posts que vous devez
,
Par exemple
'
tre capable
nous ne voulons pas que l utilisateur cr
.
é
e un post
et l assigne à quelqu un d autre
Donc nous allons utiliser le callback
certains champs
deny()
'
'é
pour permettre à l utilisateur d
:
diter seulement
Posts = new Mongo.Collection('posts');
Posts.allow({
update: function(userId, post) { return ownsDocument(userId, post); },
remove: function(userId, post) { return ownsDocument(userId, post); },
});
Posts.deny({
update: function(userId, post, fieldNames) {
// may only edit the following two fields:
return (_.without(fieldNames, 'url', 'title').length > 0);
}
});
//...
/
/
.
lib collections posts js
Commit 8-3
.
Accepter le changement de seulement certain champs
'
Voir sur GitHub
fieldNames
Nous transmettons le tableau
champs qui ne sont pas
,
Si tout se passe bien
url
,
la taille du tableau vaudra
-ê
).
é
tre remarqu
modification des posts la pr
soumettre un lien et l
è
,
posts
title .
1
ê
tre de
ou plus
,
0.
'
Si quelqu un essaie de
et le callback retournera
true
chera la mise à jour
Vous aurez peut
à ce probl
s et en
d Underscore nous obtenons un tableau qui contient les
ou
ê
ce qui emp
é
qui contient la liste des champs modifi
le tableau sera vide et sa taille devra
jouer un peu avec le code
(
’
without()
utilisant la fonction
Lancer l instance
'é
'
é
que nous ne v
é
rifions nulle part dans notre code de
é.
sence de liens dupliqu
'
s
'
Cela veut dire qu un utilisateur pourrait
diter afin de changer l URL pour passer outre la v
é
me serait d utiliser une m
thode de Meteor
é
.
rification
( Meteor.methods() )
La solution
pour modifier les
mais nous avons voulu vous montrer cela pour le principe et vous exercer
.
Les appels de méthode vs la manipulation de données ô é
c
é
Pour cr
,
er des posts
é
nous avons utilis
une m
é
thode Meteor
allow
transactions de donn
'
et
deny
client
postInsert , par
update
contre pour les modifier et les supprimer nous appelons
directement depuis le client en utilisant
t
et
remove
é
pour s
curiser les
é .
es
'
é
Quand utiliser l une ou l autre m
thode
?
Lorsque les choses sont relativement simple et que vous pouvez rapidement adapter
é
votre s
curit
é
avec
allow
et
directement depuis le client
Par contre
ôé
contr
l
,
é
Les m
.
ù
à partir du moment o
'
par l utilisateur
),
utilisateur
deny , il est plus simple de faire les opérations
(
vous devez faire des choses qui ne doivent pas
'
é
thode Meteor
Meteor.methods .
é
thodes Meteor sont aussi plus adapt
s dans certains cas
:
î
ô
Quand vous devez conna tre ou renvoyer des valeurs via un callback plut
'
é
activit
Pour les fonctions op
é
.
é
é
rant de grosses manipulations sur la base de donn
é
Pour des calculs sur la base de donn
œ
t que
et la synchronisation prennent effet
seraient trop lourdes à transmettre entre le client et le serveur
Jetez un
tre
comme dater un nouveau post ou l assigner au bon
vous devriez utiliser une m
d attendre que la r
ê
es
(
exemple
:
,
count
é
il à notre blog pour une exploration plus en d
.
average
).
,
sum
.
tail de ce sujet
es qui
Allow et Deny
è
Le syst
é
donn
é
me de s
8.5
SIDEBAR
é
ô
curit
de Meteor nous permet de contr
é
es sans avoir à d
é
finir des M
Parce que nous avions besoin de r
éé
des propri
é éé
d
jà
t
s suppl
é ,
t
post
é
.
'
é
mentaires et d
é
cider d une action sp
thode
post
'
é
aliser des tâches auxiliaires comme d
é
utiliser une M
'
thodes à chaque fois que l on fait des changements
é
e
ler les modifications de la base de
é
sp
'
corer l article avec
'
ciale quand l URL de l article
éé é
cifique quand un article est cr
é
tait
tait tout à
é.
fait sens
'
D un autre c
'
ô é,
t
é
nous n avions pas vraiment eu besoin de cr
mettre à jour ou supprimer des articles
avait la permission de r
é ,
es
é
Nous avions juste besoin de v
é
aliser ces actions
Utiliser ces callbacks nous laisse
donn
.
,
é
et cela fut facilit
ê
é
tre plus d
è
'
thodes pour
rifier si l utilisateur
par les callbacks
allow
deny .
et
claratif à propos des modifications de la base de
et dire quels types de mises à jour peuvent
avec le syst
é
er de nouvelles M
ê
é .
tre utilis
es
' '
è
Le fait qu ils s int
.
grent
me de comptes est un bonus
Multiples callbacks
é
Nous pouvons d
finir autant de callbacks
' '
’
qu au moins l un d entre eux retourne
Donc quand
c
ôé
v
t
Posts.insert
true
é
é
que n
dans un navigateur
- insert '
, '
rifications allowed
n en trouve aucune
ê
De la m
me façon
,
callbacks retourne
Nous avons juste besoin
'
é
),
'
(
'
,
il n autorisera pas le insert
nous pouvons d
le serveur va faire à son tour toutes les
'
.
et retournera une erreur
é
finir un ou plusieurs callbacks
403
deny . Si
true , le changement sera annulé et une erreur 403
aussi bien que chaque callback
.
au client
un de ces
é.
sera retourn
é
seront ex
é.
cut
s
'
S il
La
insert réussi, un ou plusieurs callbacks allow
deny insert
.
rer
peu importe si c est depuis le code
qu il peut jusqu à ce qu il en trouve une qui retourne true
logique de tout cela signifie que pour un
insert
.
cessaires
durant le changement qui est en train de s op
client de votre application ou depuis la console
é
'
est appel
allow
Note: n/e est l'abréviation de Not Executed
'
,
En d autres mots
Meteor descend la liste de callback en partant du premier avec
'
' '
deny , puis
allow , et exécute chaque callback jusqu à ce que l un d entre eux retourne true .
avec
'
'
article appartient à l utilisateur courant
'
droits d administration
.
'
,
é
et un second qui v
'
allow() , l un qui vérifie si un
Un exemple pratique de ce pattern serait d avoir deux callbacks
'
rifie si l utilisateur courant a les
Si l utilisateur courant est un administrateur
'
capable de mettre à jour n importe quel article
.
,
'
'
,
'
cela assure qu il sera
puisqu au moins l un de ces callback
retournera true
Compensation de latence
-
é
Souvenez vous que ces M
é
sont compens
en latence
é
thodes de mutation de base de donn
,
comme toutes les autres m
é
.
thodes
es
(
telles que
.update()
Donc par exemple
,
si vous
essayez de supprimer un article qui ne vous appartient pas via la console du navigateur
'
verrez l article bri
puis r
é
è
î
ù
vement dispara tre au moment o
'
î
,
appara tre lorsque le serveur l informe que
é.
)
,
vous
,
votre collection locale perd le document
'
,
non
en fait le document n a pas
éé
t
supprim
'
û
Bien s
(
è
apr
r ce comportement n est pas un probl
,
s tout
è
é
me quand il est d
é
clench
é
si les utilisateurs essaient de bidouiller avec les donn
'
passe dans leur navigateur n est pas vraiment votre probl
'
'
.
assurer que cela n arrive pas dans l interface utilisateur
è
me
).
depuis la console
es dans la console
,
Cependant
,
Par exemple
,
ce qui se
vous devez vous
vous devez vous donner
'
du mal pour vous assurer que vous ne montrez pas les boutons supprimer lorsqu ils ne sont
é
pas autoris
.
s à supprimer
,
Heureusement
(
par exemple
,
puisque vous pouvez partager le code de permissions entre client et serveur
vous pourriez
é
la mettre dans le r
é
code suppl
é
lib
pertoire
è
crire une fonction biblioth
)
é,
partag
.
que
canDeletePost(user, post)
et
cela ne requiert habituellement pas beaucoup de
mentaire
Permissions côté serveur
-
Souvenez vous que le syst
é
de donn
è
é
es initi
'
me de permissions s applique seulement sur les mutations de base
es par le client
.
Sur le serveur
,
é
Meteor assume que toutes les op
rations sont
.
permises
ù
Ceci signifie que dans le cas o
qui pourrait
article
é é
v
rifi
.
ê
tre appel
é
vous
é
é
cririez une M
,
e par le client
'
ôé
thode Meteor c
t
serveur
deletePost
n importe qui serait capable de supprimer chaque
Vous ne voulez donc probablement pas faire cela à moins que vous ayez
'
les permissions à l int
é
rieur de cette M
é
thode
.
é
galement
Erreurs
9
Utiliser simplement la boite de dialogue de navigateur standard
'
l utilisateur quand il y a un probl
'
'
è
alert()
pour avertir
'
me avec l envoi de leur formulaire n est pas tr
é
et ce n est clairement pas fait pour une bonne exp
rience utilisateur
.
è
,
s satisfaisant
Nous pouvons faire
.
mieux
,
À la place
'
é
construisons un m
'
'
canisme de rapport d erreurs plus versatile qui pr
'
mieux l utilisateur de ce qu il se passe sans l interrompre
é
Nous allons impl
menter un syst
é
sup
rieur droit de la fen
ê
,
tre
è
é
viendra
.
me simple qui affiche les nouvelles erreurs dans le coin
'
.
semblable à l application populaire Mac OS Growl
Présentation des Collections Locales
,
Pour commencer
é
nous devons cr
.
er une collection dans laquelle nous stockerons nos erreurs
'
Sachant que les erreurs sont seulement pertinentes pour la session en cours et n ont besoin
'ê
d
,
tre persistantes en aucun cas
.
collection locale
,
navigateur
,
nous allons faire quelque chose de nouveau
Cela signifie que la collection
nous cr
'
),
é
ons l erreur dans le dossier
une collection cliente uniquement
é
puisque les donn
é
e c
ôé
t
existera uniquement dans le
.
,
donn
er une
et ne fera aucune tentative de synchronisation avec le serveur
Pour accomplir cela
(
Errors
é
et cr
client
(
pour faire de la collection
avec son nom de collection MongoDB configur
é
es de cette collection ne seront jamais sauvegard
serveur
):
é
à
null
es dans la base de
// Collection Locale (client-seulement)
Errors = new Meteor.Collection(null);
/
/
.
client helpers errors js
Maintenant que la collection a
é é éé ,
t
cr
e
nous pouvons ajouter une fonction
.
nous appellerons pour y ajouter des erreurs
'
throwError
é
Nous n avons pas besoin de nous pr
que
occuper de
allow
'
deny
ou
'
è
ou d autre probl
.
me de s
é
é
curit
puisque cette collection est
“
locale
”
à
l utilisateur en cours
throwError = function(message) {
Errors.insert({message: message});
};
/
/
.
client helpers errors js
'
'
L avantage d utiliser une collection locale pour stocker les erreurs est que
,
collections
è
mani
elle est r
é
é
re r
active
ê
active de la m
–
,
é
me façon que nous affichons les donn
'
es de n importe quelle autre
.
Afficher les erreurs
Nous allons afficher les erreurs en haut de notre layout principal
:
<template name="layout">
<div class="container">
{{> header}}
{{> errors}}
<div id="main">
{{> yield}}
</div>
</div>
</template>
/
/
.
client templates application layout html
Maintenant
, é
cr
'
cela veut dire que nous pouvons afficher les erreurs d une
collection
/
comme toutes les
ons les templates
errors
et
error
dans
errors.html :
<template name="errors">
<div class="errors row-fluid">
{{#each errors}}
{{> error}}
{{/each}}
</div>
</template>
<template name="error">
<div class="alert alert-danger" role="alert">
<button type="button" class="close" data-dismiss="alert">&times;</button
>
{{message}}
</div>
</template>
/
/
/
.
client templates includes errors html
Templates jumeaux
Vous noterez que nous mettons deux templates dans un seul fichier
,
maintenant
,
mais
bien
é
nous avons essay
,
(
pour Meteor
,
é
“
rer à la convention
'
Jusqu à
un fichier
,
un template
main.html
tr
è
s confus
!).
'
ô
vu que les deux templates d erreur sont plut
une exception et les mettre dans le m
ê
,
t courts
nous allons faire
é
me fichier pour rendre notre r
pertoire un peu
.
plus clair
'
Nous avons juste besoin d int
é
grer notre helper de template
Template.errors.helpers({
errors: function() {
return Errors.find();
}
});
/
/
”,
mettre tous vos templates dans un seul fichier fonctionne aussi
bien que cela rendrait
Dans ce cas
'
d adh
.
/
.
client templates includes errors js
,
et nous seront fin pr
ê
ts
!
è
Vous pouvez d
s à pr
'
é
.
sent tester nos nouveaux messages d erreur manuellement
simplement la console de votre navigateur et tapez
:
throwError("I'm an error!");
Tester les messages d'erreur.
Commit 9-1
'
.
Rapport d erreur basique
Voir sur GitHub
'
Lancer l instance
Ouvrez
Deux Types d'Erreur
,
A ce stade
'
il est important de faire la distinction entre les erreurs au niveau de
l application
(“ -
app level
”)
'
de celles au niveau du code
Les erreurs au niveau de l application
'
l utilisateur
,
'
,
ainsi de suite
'
é
.
'
-
code level
é é
sont g
n
”).
é
ralement d
é
clench
es par
Ces erreurs comprennent notamment les
,
les erreurs de permission
'
“
les erreurs de type
”
introuvables
'
et
Ce sont le genre d erreurs que l on veut montrer à l utilisateur pour
gler tout probl
è
è
é.
me rencontr
Les erreurs au niveau du code
mani
)
app level
et l on peut agir sur celles ci
erreurs de validation
l aider à r
( -.
(“
é
re inattendue par de r
-
(
),
code level
ô é,
,
de leur c
t
els bugs dans votre code
é
sont d
,
Dans ce chapitre
es de
et vous ne voulez
,
probablement pas les afficher à vos utilisateurs directement
une trace avec un service tiers de suivi des erreurs
é
clench
(
).
'
ô
mais plut
t d en garder
tel que Kadira
'
,
nous nous concentrerons sur le premier type d erreur
.
pas sur le
suivi des bugs
Créer des erreurs
é
Nous savons d
sormais comment afficher des erreurs
avant de voir quoi que ce soit
:
erreur
alert
.
En fait
'
,
é
nous avons d
.
en place
:
postSubmit
par la nouvelle fonction
-
é
mais encore faut il en d
jà impl
notre avertissement lors d un article doublon
dans
,
é
é
ment
clencher une
é
un bon sc
nario pour une
Nous remplacerons simplement les
throwError
que nous venons de mettre
Template.postSubmit.events({
'submit form': function(e) {
e.preventDefault();
var post = {
url: $(e.target).find('[name=url]').val(),
title: $(e.target).find('[name=title]').val()
};
Meteor.call('postInsert', post, function(error, result) {
// display the error to the user and abort
if (error)
return throwError(error.reason);
// show this result but route anyway
if (result.postExists)
throwError('This link has already been posted');
}
});
/
Router.go('postPage', {_id: result._id});
});
/
/ _
client templates posts post
Tant que nous y sommes
,
.
submit js
nous allons faire la m
ê
me chose pour
postEdit :
Template.postEdit.events({
'submit form': function(e) {
e.preventDefault();
var currentPostId = this._id;
var postProperties = {
url: $(e.target).find('[name=url]').val(),
title: $(e.target).find('[name=title]').val()
}
Posts.update(currentPostId, {$set: postProperties}, function(error) {
if (error) {
// display the error to the user
throwError(error.reason);
} else {
Router.go('postPage', {_id: currentPostId});
}
});
},
//...
});
/
/
/ _
client templates posts post
.
edit js
Commit 9-2
'
Utilisation du rapport d erreurs
Voir sur GitHub
ê
Essayez par vous m
me
:
tentez de cr
é
Comme cette adresse est d
é
'
Lancer l instance
'
http://meteor.com .
er un article et entrez l adresse
é
jà attach
.
'
,
e à un article dans l installation
vous devriez voir
:
Déclencher une erreur
Effacer les Erreurs
'
-
ê
Vous noterez que les messages d erreur disparaissent par eux m
.
secondes
û
Cela est en fait d
é
avons ajout
é
e au tout d
:
@keyframes fadeOut {
0% {opacity: 0;}
10% {opacity: 1;}
90% {opacity: 1;}
100% {opacity: 0;}
}
//...
.alert {
animation: fadeOut 2700ms ease-in 0s 1 forwards;
//...
}
/
/
.
s quelques
à un peu de magie CSS incluse dans la feuille de style que nous
but de ce livre
client stylesheets style css
è
me apr
é
Nous d
é
opacit
fadeOut
finissons une animation CSS
( 0%, 10%, 90%,
à
'
%
é
L animation s ex
'
100
.alert .
animation à la classe
'
et
de la dur
2700
cutera pendant
qui pr
é
é
é
cise quatre images cl
'
)
e totale de l animation
,
millisecondes au total
éé
pour la propri
t
et appliquons cette
'é
utilisera l
quation de timing
ease-in , s exécutera avec un délai de 0 secondes, une seule fois, et finalement restera sur la
è
derni
é
re image cl
(
)
keyframe
é .
une fois termin
e
Animations contre Animations
Vous vous demandez peut
é é
ôé
pr
d
contr
termin
l
é
-ê
tre pourquoi nous utilisons des animations CSS
es et en dehors du contr
-
es par Meteor lui m
ê
me
),
ô
le de notre application
.
'
'
Bien que Meteor offre une aide à l insertion d animations
é
ê
chapitre soit focalis
“
animations CSS
Animations
.
,
Cela fonctionne bien
b
”
tes
.
é
qui sont
au lieu d animations
nous voulions que ce
'
Nous utiliserons donc pour l instant des
et garderons les choses plus sophistiqu
mais si vous d
)
trois fois par exemple
sur les erreurs
,
'
(
clenchez plusieurs erreurs
'
'
(
é
es pour le chapitre
en soumettant le m
ê
me lien
vous remarquerez qu elles s empileront les unes au dessus des autres
:
Débordement de pile.
éé
Et cela parce que alors que les
é
toujours pr
'
l
.
sents dans le DOM
ments
.alert
,
disparaissent visuellement
é
Nous devons r
.
gler cela
.
C est exactement dans ce genre de situation que Meteor brille
é
est r
,
active
Puisque la collection
é
tout ce que nous devons faire pour nous d
les supprimer de la collection
ils sont en fait
!
`
’
Errors
barrasser de ces vieilles erreurs est de
Nous utiliserons
fin du timeout
(
Meteor.setTimeout
, 3000
dans ce cas
é
pour sp
cifier une fonction callback à
).
millisecondes
ê
é
tre ex
é
cut
e à la
Template.errors.helpers({
errors: function() {
return Errors.find();
}
});
Template.error.onRendered(function() {
var error = this.data;
Meteor.setTimeout(function () {
Errors.remove(error._id);
}, 3000);
});
/
/
/
.
client templates includes errors js
Commit 9-3
Effacer les erreurs apr
Voir sur GitHub
Le callback
'
é
À l int
onRendered
rieur du callback
'
, this
é
nous permet d acc
).
é
est d
é
clench
éè
se r
der aux donn
f
è 3
s
.
secondes
'
Lancer l instance
éé
une fois notre template interpr
'
t
.
dans le navigateur
,
re à l instance courante du template
'
é
'
é
es de l objet en cours d interpr
tation
(
this.data
et
une erreur dans
notre cas
Mettre en place une validation
'
,
Jusqu ici
,
minimum
.
post
'
nous n avons pas impos
é
une quelconque validation de notre formulaire
Au
nous voulons que les utilisateurs fournissent une URL et un titre pour leur nouveau
-
'
Assurons nous donc qu ils le font
.
é :
Nous allons faire deux choses pour signaler les champs non renseign
allons donner une classe sp
é
probl
.
é
ciale CSS
.
matique du formulaire
.
dessous du champ
Puis
,
has-error
au
div
s
'
è
premi
,
rement
nous
parent de n importe quel champ
'
nous allons afficher un message d erreur utile juste en
Pour commencer
helpers
, é
pr
parons notre template
postSubmit
'
pour qu il accepte ces nouveaux
:
<template name="postSubmit">
<form class="main form page">
<div class="form-group {{errorClass 'url'}}">
<label class="control-label" for="url">URL</label>
<div class="controls">
<input name="url" id="url" type="text" value="" placeholder="Your UR
L" class="form-control"/>
<span class="help-block">{{errorMessage 'url'}}</span>
</div>
</div>
<div class="form-group {{errorClass 'title'}}">
<label class="control-label" for="title">Title</label>
<div class="controls">
<input name="title" id="title" type="text" value="" placeholder="Nam
e your post" class="form-control"/>
<span class="help-block">{{errorMessage 'title'}}</span>
</div>
</div>
<input type="submit" value="Submit" class="btn btn-primary"/>
</form>
</template>
/
/
/ _
client templates posts post
.
submit html
è
Notez que nous transmettons des param
.
helper
Cela nous permet de r
tres
é
ê
utiliser le m
comportement selon le param
è
(
.
,
changera
ce qui
,
,
à son tour
title
)
à chaque
en modifiant son
.
:
rendre ces helpers r
Nous utiliserons Session pour stocker un objet
'
,
me helper chaque fois
et
tre
Abordons maintenant la partie amusante
messages d erreurs potentiels
url
respectivement
'
é
.
ellement fonctionnels
postSubmitErrors
contenant tous les
Pendant que l utilisateur interagit avec le formulaire
,
cet objet
mettra à jour activement la mise en page et le contenu du
.
formulaire
,
En premier lieu
'
nous initialiserons l objet à chaque fois que le template
'
'
'
postSubmit
Cela assure que l utilisateur ne verra pas d anciens messages d erreur laiss
é
s par une
éé.
est cr
éé
pr
c
.
dente visite de cette page
é
Nous d
field
.
finirons ensuite nos deux helpers de template
'ù
lieu d o
é
).
( ù field
o
est soit
url
ou
title
t
selon le
on appelle le helper
Alors que
pr
Session.get('postSubmitErrors')
de
éé
Ils regardent tous les deux la propri
errorMessage
'
-
renvoie simplement lui m
sence d un message et renvoie
has-error
'
ê
, errorClass é
me le message
v
rifie la
.
s il en existe un
Template.postSubmit.onCreated(function() {
Session.set('postSubmitErrors', {});
});
Template.postSubmit.helpers({
errorMessage: function(field) {
return Session.get('postSubmitErrors')[field];
},
errorClass: function (field) {
return !!Session.get('postSubmitErrors')[field] ? 'has-error' : '';
}
});
//...
/
/
/ _
client templates posts post
.
submit js
Vous pouvez tester que nos helpers fonctionnent normalement en ouvrant le navigateur et en
tapant la ligne de code suivante
:
Session.set('postSubmitErrors', {title: 'Attention ! Intrusion détectée. Le
s robots-chiens sont lâchés.'});
Browser console
Code rouge ! Code rouge !
La prochaine
é
tape est de hooker cet objet de session
,
Avant de faire ça
'
regarde l objet
,
savoir
postSubmitErrors
é
nous allons cr
er une nouvelle fonction
post , et renvoie un objet errors
si les champs
title
ou
url
):
//...
validatePost = function (post) {
var errors = {};
if (!post.title)
errors.title = "Please fill in a headline";
}
return errors;
//...
/
/
.
lib collections posts js
dans
posts.js
qui
contenant toutes les erreurs pertinentes
sont manquant
if (!post.url)
errors.url = "Please fill in a URL";
validatePost
.
au formulaire
(
à
'é é
Nous appellerons cette fonction depuis le helper d
v
nement
postSubmit :
Template.postSubmit.events({
'submit form': function(e) {
e.preventDefault();
var post = {
url: $(e.target).find('[name=url]').val(),
title: $(e.target).find('[name=title]').val()
};
var errors = validatePost(post);
if (errors.title || errors.url)
return Session.set('postSubmitErrors', errors);
Meteor.call('postInsert', post, function(error, result) {
// affiche l'erreur à l'utilisateur et s'interrompt
if (error)
return throwError(error.reason);
// affiche ce résultat mais route quand même
if (result.postExists)
throwError('This link has already been posted');
}
});
Router.go('postPage', {_id: result._id});
});
/
/
/ _
client templates posts post
Notez que nous utilisons
é
pr
,
sente
.
submit js
return
'
é
pour interrompre l ex
é
pas parce que nous voulons r
cution du helper si une erreur est
.
ellement renvoyer cette valeur quelque part
Pris la main dans le sac.
Validation côté serveur
'
.
Nous n avons pas tout à fait fini
'
-
mais qu en est il du serveur
?
è
Apr
,
s tout
é
vide manuellement en appelant la m
'
ê
M
'
'
'
é
Nous validons la pr
'
'
quelqu un pourrait toujours essayer d entrer un post
thode
postInsert
ê
'
é
depuis l int
me fonction
é
rieur de la m
,
thode
.
depuis la console du navigateur
'
,
me si nous n avons pas besoin d afficher de messages d erreur sur le serveur
toujours utiliser la m
,
sence d une URL et d un titre sur le client
'
nous pouvons
validatePost . Sauf que cette fois, nous l appellerons aussi
'é é
pas seulement depuis le helper d
v
nement
:
Meteor.methods({
postInsert: function(postAttributes) {
check(this.userId, String);
check(postAttributes, {
title: String,
url: String
});
var errors = validatePost(postAttributes);
if (errors.title || errors.url)
throw new Meteor.Error('invalid-post', "You must set a title and URL f
or your post");
var postWithSameLink = Posts.findOne({url: postAttributes.url});
if (postWithSameLink) {
return {
postExists: true,
_id: postWithSameLink._id
}
}
var user = Meteor.user();
var post = _.extend(postAttributes, {
userId: user._id,
author: user.username,
submitted: new Date()
});
var postId = Posts.insert(post);
}
});
return {
_id: postId
};
/
/
.
lib collections posts js
Une fois de plus
é
devez d
,
les utilisateurs ne devraient normalement jamais voir ce message
finir un titre et une URL pour votre post
'
».
'
«
:
'
Cela ne s affichera que si quelqu un veut
é
contourner l interface utilisateur que nous avons m
ticuleusement mise en place
,
et utiliser
.
directement la console à la place
,
Pour tester ça
Vous
'
ouvrez la console du navigateur et essayez d entrer un post sans URL
:
Meteor.call('postInsert', {url: '', title: 'No URL here!'});
,
Si nous avons fait notre travail proprement
effrayant avec le message
«
é
Vous devez d
é
vous devriez voir en retour une flop
e de code
finir un titre et une URL pour votre post
Commit 9-4
».
.
Validation du contenu du post au moment de la soumission
Voir sur GitHub
'
Lancer l instance
Validation des éditions
,
Pour arrondir les angles
’é
d
.
dition
ê
nous allons aussi appliquer la m
Le code sera plut
ô
.
t similaire
'
me validation pour notre formulaire
D abord le template
:
<template name="postEdit">
<form class="main form page">
<div class="form-group {{errorClass 'url'}}">
<label class="control-label" for="url">URL</label>
<div class="controls">
<input name="url" id="url" type="text" value="{{url}}" placeholder="
Your URL" class="form-control"/>
<span class="help-block">{{errorMessage 'url'}}</span>
</div>
</div>
<div class="form-group {{errorClass 'title'}}">
<label class="control-label" for="title">Title</label>
<div class="controls">
<input name="title" id="title" type="text" value="{{title}}" placeho
lder="Name your post" class="form-control"/>
<span class="help-block">{{errorMessage 'title'}}</span>
</div>
</div>
<input type="submit" value="Submit" class="btn btn-primary submit"/>
<hr/>
<a class="btn btn-danger delete" href="#">Delete post</a>
</form>
</template>
/
/
/ _
client templates posts post
.
edit html
Puis les helpers du template
:
Template.postEdit.onCreated(function() {
Session.set('postEditErrors', {});
});
Template.postEdit.helpers({
errorMessage: function(field) {
return Session.get('postEditErrors')[field];
},
errorClass: function (field) {
return !!Session.get('postEditErrors')[field] ? 'has-error' : '';
}
});
Template.postEdit.events({
'submit form': function(e) {
e.preventDefault();
var currentPostId = this._id;
var postProperties = {
url: $(e.target).find('[name=url]').val(),
title: $(e.target).find('[name=title]').val()
}
var errors = validatePost(postProperties);
if (errors.title || errors.url)
return Session.set('postEditErrors', errors);
Posts.update(currentPostId, {$set: postProperties}, function(error) {
if (error) {
// affiche l'erreur à l'utilisateur
throwError(error.reason);
} else {
Router.go('postPage', {_id: currentPostId});
}
});
},
'click .delete': function(e) {
e.preventDefault();
}
});
if (confirm("Supprimer ce post ?")) {
var currentPostId = this._id;
Posts.remove(currentPostId);
Router.go('postsList');
}
/
/
/ _
client templates posts post
.
edit js
,
Tout comme nous avons fait pour le formulaire de soumission de post
ôé
valider nos posts c
pour
t
é
.
diter les posts
.
serveur
À part
,
-
,
rappelez vous
update
mais un appel direct à
'
nous voulons aussi
é
que nous n utilisons pas de m
thode
.
depuis le client
Cela signifie que nous devrons ajouter un nouveau callback
deny
à la place
:
//...
Posts.deny({
update: function(userId, post, fieldNames, modifier) {
var errors = validatePost(modifier.$set);
return errors.title || errors.url;
}
});
//...
/
/
.
lib collections posts js
'
Notez que l argument
,
mise à jour
modifier
se r
(
.
re au post existant
validatePost
'
que l objet
post
modifier.$set
en entier
.
partielle qui concerne seulement
ê
è
tre un probl
-ê
Vous remarquerez peut
multiples callbacks
cela veut dire que
Dans ce cas
,
nous voulons valider la
é é $set
sur le contenu de la propri
)
t
de
Posts.update({$set: {title: ..., url: ...}}) .
comme dans
devrait pas
f
ce pourquoi nous appelons
Cela fonctionne parce que
url
éè
post
û,
Bien s
title
r
ê
contient les deux m
'
é é title
mes propri
t
s
et
cela signifie que n importe quelle mise à jour
ou
url
,
ne fonctionnera pas
mais en pratique ça ne
.
me
'
tre que c est notre second callback
'
' '
'
deny . Lorsqu on ajoute de
deny , l opération échouera si l un d entre eux renvoie true . Dans ce cas,
update
'
ne fonctionnera que s il cible seulement les champs
'
url , ou si aucun des deux n est vide.
title
et
Commit 9-5
Valider le contenu des posts lors des
Voir sur GitHub
'
é
ditions
Lancer l instance
.
Créer un Package Meteor
Nous avons construit un pattern r
'
?
9.5
SIDEBAR
é
utilisable avec notre travail sur les erreurs
,
donc pourquoi
é
ne pas l empaqueter dans un paquet intelligent et le partager avec le reste de la communaut
Meteor
ê
Pour
ê ,
tre pr
ts
'
é
nous devons nous assurer d avoir un compte d
.
,
pouvez revendiquer le votre sur meteor com
quand vous vous
'
ê
tes inscrits pour le livre
'
!
veloppeur Meteor
'
-
le votre à celui ci
è
Premi
,
rement
.
Dans tous les cas
tmeasday
nous avons besoin de cr
utiliser la commande
éé
Meteor a cr
'
é
l int
rieur
.
,
î
dans ce chapitre
vous pouvez substituez
.
é packages/tmeasday:errors/ ,
,
–
er une structure pour notre paquet
é
diter
jà fait
.
é
un dossier nomm
comment il doit utiliser le paquet
é
vous devez conna tre votre nom
meteor create --package tmeasday:errors
Nous allons commencer par
Vous
mais il est fort probable que vous l ayez d
d utilisateur car nous allons l utiliser intensivement dans ce chapitre
Nous allons utiliser le nom d utilisateur
'
.
Nous pouvons
pour cela
.
Notez que
avec quelques fichiers à
package.js , le fichier qui informe à Meteor
'
et quels objets et fonctions il a besoin d exporter
.
Package.describe({
name: "tmeasday:errors",
summary: "A pattern to display application errors to the user",
version: "1.0.0"
});
Package.onUse(function (api, where) {
api.versionsFrom('0.9.0');
api.use(['minimongo', 'mongo-livedata', 'templating'], 'client');
api.addFiles(['errors.js', 'errors_list.html', 'errors_list.js'], 'client'
);
if (api.export)
api.export('Errors');
});
/
:
/
.
packages tmeasday errors package js
é
Quand on d
é
veloppe un paquet pour un usage destin
pratique de remplir la section
(
git
du bloc
,
utilisateurs peuvent lire le code source
readme
Package.describe
)
el
'
c est une bonne
avec les URL Git de votre repo
https://github.com/tmeasday/meteor-errors.git . De cette manière, les
comme
(
é ,
au monde r
)
î
et
(
)
en supposant que vous utilisez GitHub
.
-
le lisez moi
de votre paquet appara tra sur Atmosphere
Ajoutons trois fichiers au paquet
.
Nous pouvons r
é
é
cup
rer ces trois fichiers de Microscope sans
é è
trop de changements à part pour certains espaces de noms propres et une API l
plus claire
g
rement
:
Errors = {
// Collection local (client seulement)
collection: new Mongo.Collection(null),
throw: function(message) {
Errors.collection.insert({message: message, seen: false})
}
};
/
:
/
.
packages tmeasday errors errors js
<template name="meteorErrors">
<div class="errors">
{{#each errors}}
{{> meteorError}}
{{/each}}
</div>
</template>
<template name="meteorError">
<div class="alert alert-danger" role="alert">
<button type="button" class="close" data-dismiss="alert">&times;</button
>
{{message}}
</div>
</template>
/
/
:
_
packages tmeasday errors errors
.
list html
Template.meteorErrors.helpers({
errors: function() {
return Errors.collection.find();
}
});
Template.meteorError.rendered = function() {
var error = this.data;
Meteor.setTimeout(function () {
Errors.collection.remove(error._id);
}, 3000);
};
/
/
:
_
packages tmeasday errors errors
.
list js
Tester le paquet avec Microscope
Nous allons tester maintenant les choses localement avec Microscope pour nous assurer que
notre code modifi
é
.
fonctionne
,
Pour relier le paquet dans notre projet
é
nous ex
cutons
meteor add tmeasday:errors . Ensuite, nous avons besoin de supprimer les fichiers existants
qui ont
éé
t
rendu redondants par le nouveau paquet
:
rm client/helpers/errors.js
rm client/templates/includes/errors.html
rm client/templates/includes/errors.js
Suppression des vieux fichiers via la console bash
'
Une autre chose que nous avons besoin de faire est d effectuer quelques mises à jour
'
mineures pour utiliser l API correctement
{{> header}}
{{> meteorErrors}}
:
/
/
/
.
client templates application layout html
Meteor.call('postInsert', post, function(error, result) {
if (error) {
// affiche l'erreur à l'utilisateur
Errors.throw(error.reason);
/
/
/ _
.
client templates posts post
submit js
Posts.update(currentPostId, {$set: postProperties}, function(error) {
if (error) {
// Afficher l'erreur à l'utilisateur
Errors.throw(error.reason);
// affiche ce résultat mais route quand même
if (result.postExists)
Errors.throw('Ce lien à déjà été utilisé');
/
/
/ _
client templates posts post
.
edit js
Commit 9-5-1
é
Cr
'
Voir sur GitHub
Une fois que ces changements ont
-
é
original pr
paquet
.
er des erreurs basiques et les relier
éé
t
faits
,
Lancer l instance
nous devrions r
é
é
cup
rer notre comportement
.
Ecrire des Tests
è é
La premi
re
é
tape quand on d
'é
la suivante est d
,
veloppe un paquet est de le tester dans une application
mais
.
crire une suite de test qui teste proprement le comportement du paquet
Meteor propose Tinytest
(
)
é é,
un testeur de paquet int
gr
'
é
qui rend facile l ex
cution de ce type
.
de tests et permet de rester serein quand on partage notre paquet avec les autres
é
Cr
é
ons un fichier de test qui utilise Tinytest pour ex
errors
cuter des tests sur le code du paquet
:
Tinytest.add("Errors - collection", function(test) {
test.equal(Errors.collection.find({}).count(), 0);
Errors.throw('A new error!');
test.equal(Errors.collection.find({}).count(), 1);
Errors.collection.remove({});
});
Tinytest.addAsync("Errors - template", function(test, done) {
Errors.throw('A new error!');
test.equal(Errors.collection.find({}).count(), 1);
// render the template
UI.insert(UI.render(Template.meteorErrors), document.body);
Meteor.setTimeout(function() {
test.equal(Errors.collection.find({}).count(), 0);
done();
}, 3500);
});
/
/
:
_
packages tmeasday errors errors
é
Dans ces tests nous v
'
è
qu une deuxi
.
tests js
rifions que les fonctions basiques
é
me v
rification que le code
é
Nous ne couvrirons pas les sp
'
n est pas encore finalis
é
cificit
é
'é
s d
rendered
,
fonctionnent
ainsi
.
dans le template fonctionne encore
criture des tests de paquets Meteor ici
e et hautement changeante
é.
Meteor.Errors
),
(
'
comme l API
mais heureusement son fonctionnement
est assez bien expliqu
Pour dire à Meteor comment ex
é
cuter les tests dans
package.js , utilisez le code suivant :
Package.onTest(function(api) {
api.use('tmeasday:errors', 'client');
api.use(['tinytest', 'test-helpers'], 'client');
api.addFiles('errors_tests.js', 'client');
});
/
/
:
.
packages tmeasday errors package js
Commit 9-5-2
.
Ajout des tests du paquet
Voir sur GitHub
é
Puis nous pouvons ex
cuter les tests avec
:
meteor test-packages tmeasday:errors
Terminal
'
Lancer l instance
Passer tous les tests
Déployer le paquet
Maintenant
,
é
nous voulons d
livrer le paquet et le rendre disponible à tout le monde
faisons ça en le mettant sur le serveur de paquets de Meteor
Atmopshere
Nous
é
et en le d
ployant sur
.
,
Heureusement
lancer
,
.
'
c est tr
è
.
s facile
Il suffit de se rendre dans le dossier du paquet
meteor publish --create :
(
via
)
cd , et de
cd packages/tmeasday:errors
meteor publish --create
Terminal
é
Maintenant que le paquet est d
directement
é,
ploy
nous pouvons le supprimer du projet puis le rajouter
:
rm -r packages/errors
meteor add tmeasday:errors
Terminal
(
lanc
é
'
)
depuis la racine de l application
Commit 9-5-4
é
Paquet supprim
Voir sur GitHub
éé
Maintenant nous devrions voir Meteor t
é
Bien jou
!
l
é
du dossier de d
veloppement
'
Lancer l instance
è
charger notre paquet pour la toute premi
.
re fois
'
Comme d habitude avec les apart
continuer
(
-
é,
s
'
-
'
assurez vous d annuler les changements avant de
ou sinon assurez vous d en tenir compte en suivant le reste du livre
).
Commentaires
10
'
é
Le but d un site de nouvelles sociales est de cr
é
er une communaut
'
,
d utilisateurs
.
difficile à atteindre sans fournir aux gens un moyen de communiquer entre eux
donc dans ce chapitre ajouter les commentaires
!
Nous allons
Nous allons commencer par ajouter une nouvelle collection pour y enregistrer les
commentaires et quelques donn
é
es basiques pr
é
Comments = new Mongo.Collection('comments');
/
/
.
lib collections comments js
é .
enregistr
es
et cela sera
// Données préenregistrées
if (Posts.find().count() === 0) {
var now = new Date().getTime();
// crée deux utilisateurs
var tomId = Meteor.users.insert({
profile: { name: 'Tom Coleman' }
});
var tom = Meteor.users.findOne(tomId);
var sachaId = Meteor.users.insert({
profile: { name: 'Sacha Greif' }
});
var sacha = Meteor.users.findOne(sachaId);
var telescopeId = Posts.insert({
title: 'Introducing Telescope',
userId: sacha._id,
author: sacha.profile.name,
url: 'http://sachagreif.com/introducing-telescope/',
submitted: new Date(now - 7 * 3600 * 1000)
});
Comments.insert({
postId: telescopeId,
userId: tom._id,
author: tom.profile.name,
submitted: new Date(now - 5 * 3600 * 1000),
body: "C'est un projet intéressant Sacha, est-ce-que je peux y participe
r ?"
});
Comments.insert({
postId: telescopeId,
userId: sacha._id,
author: sacha.profile.name,
submitted: new Date(now - 3 * 3600 * 1000),
body: 'Bien sûr Tom !'
});
Posts.insert({
title: 'Meteor',
userId: tom._id,
author: tom.profile.name,
url: 'http://meteor.com',
submitted: new Date(now - 10 * 3600 * 1000)
});
Posts.insert({
title: 'The Meteor Book',
userId: tom._id,
}
author: tom.profile.name,
url: 'http://themeteorbook.com',
submitted: new Date(now - 12 * 3600 * 1000)
});
/
.
server fixtures js
'
'
N oublions pas de publier dans notre nouvelle collection et d y souscrire
:
Meteor.publish('posts', function() {
return Posts.find();
});
Meteor.publish('comments', function() {
return Comments.find();
});
/
.
server publications js
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() {
return [Meteor.subscribe('posts'), Meteor.subscribe('comments')];
}
});
/
.
lib router js
Commit 10-1
Avec la collection de commentaires
Voir sur GitHub
é
Notez que pour d
é
clencher ce code de donn
,
,
la publication
…
la so
'
Lancer l instance
es pr
é
enregistr
é ,
es
il faudra faire un
meteor
reset
é
pour remettre à z
é .
ro votre base de donn
es
é
cr
Apr
è
s avoir r
é
é,
initialis
'
n oubliez pas de
.
er un nouveau compte et de vous reconnecter
'
Nous avons tout d abord cr
dans la base de donn
é ,
es
é .
es
utilisateur sur le premier post
'
(
(
un couple d utilisateurs
),
factices
id
et nous pourrons utiliser leur
dehors de la base de donn
l utilisateur
'
éé
)
,
é
Ensuite nous avons ajout
é
nous les avons enregistr
plus tard pour les r
éé
f
s
rencer en
un commentaire pour chaque
en liant le commentaire avec le post
(
postId
via
)
et avec
userId . Nous avons aussi ajouté une date de publication et un body à
via
,
chaque commentaire
Nous avons aussi am
author , un champ dénormalisé.
en plus de
é
lior
é
notre router pour attendre un tableau
.
(
array
)
contenant à la fois les
commentaires et les souscriptions aux posts
Afficher les commentaires
'
è
C est tr
'
é ,
s bien d ajouter des commentaires à la base de donn
afficher sur la page de discussion
,
familier
.
,
Heureusement
et vous devriez avoir une id
é
e des
<template name="postPage">
<div class="post-page page">
{{> postItem}}
<ul class="comments">
{{#each comments}}
{{> commentItem}}
{{/each}}
</ul>
</div>
</template>
/
/
/ _
client templates posts post
.
page html
é
es
mais nous voulons aussi les
ce processus devrait vous
tapes à r
é
aliser
:
ê
tre maintenant
Template.postPage.helpers({
comments: function() {
return Comments.find({postId: this._id});
}
});
/
/
/ _
client templates posts post
é
Nous ins
.
page js
{{#each comments}}
rons le bloc
é
,
rieur du template de post
'
é
s à ce post via l attribut
templates
de
template
est
postId .
Sachant ce que nous avons appris à propos des helpers et de Spacebars
commentaire est plut
this
donc
comments . Pour trouver les commentaires pertinents, nous vérifions
un post dans le helper
ceux qui sont li
'
à l int
ô
.
t simple
é
Nous allons cr
'
er un nouveau dossier
,
é
repr
senter un
comments
'
é
à l int
rieur
pour y stocker toute l information de nos commentaires et un nouveau
commentItem :
<template name="commentItem">
<li>
<h4>
<span class="author">{{author}}</span>
<span class="date">on {{submittedText}}</span>
</h4>
<p>{{body}}</p>
</li>
</template>
/
/
/
_
client templates comments comment
.
item html
é
Cr
ons donc un rapide helper de template pour repr
format plus convivial
:
Template.commentItem.helpers({
submittedText: function() {
return this.submitted.toString();
}
});
é
senter notre date
submitted
dans un
/
/
/
_
client templates comments comment
.
item js
Nous allons ensuite afficher le nombre de commentaires de chaque post
:
<template name="postItem">
<div class="post">
<div class="post-content">
<h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
<p>
Rédigé par {{author}},
<a href="{{pathFor 'postPage'}}">{{commentsCount}} commentaires</a>
{{#if ownPost}}<a href="{{pathFor 'postEdit'}}">Edit</a>{{/if}}
</p>
</div>
<a href="{{pathFor 'postPage'}}" class="discuss btn btn-default">Comment
er</a>
</div>
</template>
/
/
/ _
client templates posts post
Et ajouter le helper
.
item html
commentsCount
à
post_item.js :
Template.postItem.helpers({
ownPost: function() {
return this.userId === Meteor.userId();
},
domain: function() {
var a = document.createElement('a');
a.href = this.url;
return a.hostname;
},
commentsCount: function() {
return Comments.find({postId: this._id}).count();
}
});
/
/
/ _
client templates posts post
.
item js
Commit 10-2
Affichage des commentaires sur
ê
postPage
`.
'
Voir sur GitHub
Vous devriez maintenant
`
Lancer l instance
'
quelque chose comme ça
tre capable d afficher nos commentaires pr
:
é
é
enregistr
s et voir
Affichage des commentaires
Publier des commentaires
é
Ajoutons un moyen pour nos utilisateurs de cr
.
er de nouveaux commentaires
é é
Le proc
d
é
nous allons suivre est similaire à la façon dont nous avons permis à nos utilisateurs de cr
.
nouveaux posts
Nous allons commencer par ajouter un bouton de publication en bas de chaque post
:
que
er de
<template name="postPage">
<div class="post-page page">
{{> postItem}}
<ul class="comments">
{{#each comments}}
{{> commentItem}}
{{/each}}
</ul>
{{#if currentUser}}
{{> commentSubmit}}
{{else}}
<p>Please log in to leave a comment.</p>
{{/if}}
</div>
</template>
/
/
/ _
client templates posts post
En ensuite cr
.
page html
é
er le template du formulaire de commentaire
:
<template name="commentSubmit">
<form name="comment" class="comment-form form">
<div class="form-group {{errorClass 'body'}}">
<div class="controls">
<label for="body">Réagir à ce post</label>
<textarea name="body" id="body" class="form-control" rows="3"></text
area>
<span class="help-block">{{errorMessage 'body'}}</span>
</div>
</div>
<button type="submit" class="btn btn-primary">Add Comment</button>
</form>
</template>
/
/
/
_
client templates comments comment
,
Pour publier nos commentaires
è
comment_submit.js
publications de posts
qui op
:
.
submit html
é
nous appelons une M
'
è
re d une mani
thode
comment
dans
re similaire à ce que nous avons fait pour les
Template.commentSubmit.onCreated(function() {
Session.set('commentSubmitErrors', {});
});
Template.commentSubmit.helpers({
errorMessage: function(field) {
return Session.get('commentSubmitErrors')[field];
},
errorClass: function (field) {
return !!Session.get('commentSubmitErrors')[field] ? 'has-error' : '';
}
});
Template.commentSubmit.events({
'submit form': function(e, template) {
e.preventDefault();
var $body = $(e.target).find('[name=body]');
var comment = {
body: $body.val(),
postId: template.data._id
};
var errors = {};
if (! comment.body) {
errors.body = "Please write some content";
return Session.set('commentSubmitErrors', errors);
}
Meteor.call('commentInsert', comment, function(error, commentId) {
if (error){
throwError(error.reason);
} else {
$body.val('');
}
});
}
});
/
/
/
_
client templates comments comment
.
submit js
éé
Tout comme nous avons pr
,
serveur
c
é
demment mis en place une M
é
nous allons mettre en place une M
,
commentaires
'
thode Meteor
,
s assurer que tout est conforme
commentaire dans la collection
‘
’.
comments
thode Meteor
comment
é
et finalement ins
pour cr
post côté
é
er nos
rer le nouveau
Comments = new Mongo.Collection('comments');
Meteor.methods({
commentInsert: function(commentAttributes) {
check(this.userId, String);
check(commentAttributes, {
postId: String,
body: String
});
var user = Meteor.user();
var post = Posts.findOne(commentAttributes.postId);
if (!post)
throw new Meteor.Error('invalid-comment', 'Vous devez commenter sur un
post');
comment = _.extend(commentAttributes, {
userId: user._id,
author: user.username,
submitted: new Date()
});
}
});
/
return Comments.insert(comment);
/
.
lib collections comments js
Commit 10-3
Avec le formulaire de publication de commentaires
'
Voir sur GitHub
,
Cela ne fait rien de bien fantaisiste
le commentaire a un corps
(
),
body
'
'
Lancer l instance
'
é,
on s assure simplement que l utilisateur est connect
é
et qu il est li
.
au post
que
Le formulaire de publication de commentaires
Contrôle de la publication de commentaires
'é
Dans l
,
tat des choses
é.
clients connect
'
s
nous publions tous les commentaires à travers les posts à tous les
é
Cela semble un peu d
.
é
qu une petite partie de ces donn
è
raisonnable
.
es à tout moment
Apr
,
s tout
'
é
Am
,
Si nous y pensons
commentaires
é.
ler exactement quels commentaires sont publi
ù
le seul moment o
'
re
.
é
'
,
Jusqu à maintenant
re dont nous souscrivons à nos
,
nous avons souscrit au niveau du routeur
é
û
tre doit bien s
é
besoin de d
.
s à ce post particulier
'
ce qui signifie
é.
es d un seul coup lorsque le routeur est initialis
é
Mais nous voulons maintenant que notre souscription d
è
et nous avons
è
que nous chargeons toutes nos donn
param
,
de à la page individuelle d un post
tape consistera à changer la mani
commentaires
'
è
est lorsqu un utilisateur acc
è é
s
on a besoin de souscrire à la publication de nos
besoin de charger uniquement les commentaires reli
La premi
ellement
liorons donc nos publications et
ô
souscriptions pour contr
é
nous n utilisons r
'
'
è
pende d un param
.
r pouvoir changer à n importe quel moment
,
tre chemin
et ce
Nous allons donc avoir
.
placer notre code de souscription du niveau du routeur à celui des routes
é
Cela a une autre cons
,
appli
quence
:
é
au lieu de charger nos donn
es quand nous initialisons notre
nous les chargerons maintenant à chaque fois que notre route sera atteinte
'
.
Cela veut
'
,
dire que vous aurez maintenant des temps de chargement pendant l utilisation de l appli
'
mais c est un inconv
'
é
l ensemble des donn
è
Premi
,
rement
configure
nient in
é
vitable à moins que vous ne pr
é
es au d
but
nous allons arr
en supprimant
éé
nous avions pr
é
c
demment
ê
é
é
voyiez de charger d
finitivement
.
é
ter de pr
charger tous les commentaires dans le bloc
Meteor.subscribe('comments')
):
(
autrement dit revenir à ce que
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() {
return Meteor.subscribe('posts');
}
});
/
.
lib router js
Et nous allons ajouter une nouvelle fonction
waitOn
de niveau route pour la route
postPage :
//...
Router.route('/posts/:_id', {
name: 'postPage',
waitOn: function() {
return Meteor.subscribe('comments', this.params._id);
},
data: function() { return Posts.findOne(this.params._id); }
});
//...
/
.
lib router js
Nous passons
this.params._id
'
'
.
en tant qu argument à la souscription
é
nouvelle information pour s assurer de restreindre notre lot de donn
appartenant au post courant
Utilisons donc cette
es aux commentaires
:
Meteor.publish('posts', function() {
return Posts.find();
});
Meteor.publish('comments', function(postId) {
check(postId, String);
return Comments.find({postId: postId});
});
/
.
server publications js
Commit 10-4
/
…
Avec une simple publication souscription pour les comment
Voir sur GitHub
'
'
Il n y a qu un seul probl
'
è
me
,
'
Lancer l instance
'
,
quand nous retournons à la page d accueil
nos posts n ont aucun commentaires
:
é
il pr
tend que tous
Nos commentaires ont disparu !
Compter les commentaires
î
ô
La raison va nous appara tre bient
:
nous ne chargeons les commentaires que sur la
postPage , donc lorsque nous appelons Comments.find({postId: this._id})
route
helper
é
.
sultat
é
La meilleure façon de r
'ê
si vous n
'
dans le
commentsCount , Meteor ne peut pas trouver les données nécessaires côté client pour
nous fournir un r
(
t claire
!).
é,
,
r de savoir ce que cela veut dire
é
ne vous inqui
,
Bien que comme nous allons le voir
complexifi
normaliser le nombre de commentaires sur le post
û
tes pas s
s occupe de vous
é
gler cela est de d
n
'
é
le prochain apart
é è
notre code s en retrouve l
é é
le b
,
tez pas
g
rement
fice de performance que nous retirons de ne pas avoir à publier tous les
.
commentaires pour afficher le post en vaut le coup
é é commentsCount
Nous allons terminer ça en ajoutant une propri
t
é
à la structure de donn
post . Nous allons commencer par mettre à jour nos données préenregistrées de posts
du
meteor reset
faire
)
è :
apr
s
pour les recharger
–'
é
n oubliez pas de recr
er votre compte utilisateur
es
(
et
// Données préenregistrées
if (Posts.find().count() === 0) {
var now = new Date().getTime();
// create two users
var tomId = Meteor.users.insert({
profile: { name: 'Tom Coleman' }
});
var tom = Meteor.users.findOne(tomId);
var sachaId = Meteor.users.insert({
profile: { name: 'Sacha Greif' }
});
var sacha = Meteor.users.findOne(sachaId);
var telescopeId = Posts.insert({
title: 'Introducing Telescope',
userId: sacha._id,
author: sacha.profile.name,
url: 'http://sachagreif.com/introducing-telescope/',
submitted: new Date(now - 7 * 3600 * 1000),
commentsCount: 2
});
Comments.insert({
postId: telescopeId,
userId: tom._id,
author: tom.profile.name,
submitted: new Date(now - 5 * 3600 * 1000),
body: 'Interesting project Sacha, can I get involved?'
});
Comments.insert({
postId: telescopeId,
userId: sacha._id,
author: sacha.profile.name,
submitted: new Date(now - 3 * 3600 * 1000),
body: 'Bien sûr Tom !'
});
Posts.insert({
title: 'Meteor',
userId: tom._id,
author: tom.profile.name,
url: 'http://meteor.com',
submitted: new Date(now - 10 * 3600 * 1000),
commentsCount: 0
});
Posts.insert({
title: 'The Meteor Book',
userId: tom._id,
author: tom.profile.name,
url: 'http://themeteorbook.com',
submitted: new Date(now - 12 * 3600 * 1000),
commentsCount: 0
});
}
/
.
server fixtures js
'
,
Comme d habitude lorsque nous mettons à jour notre fichier fixtures
meteor reset
,
Puis
sur votre base de donn
'
é
vous devez lancer
é.
e pour vous assurer qu il sera relanc
é
nous nous assurons que tous les nouveaux posts d
butent avec
0
commentaire
:
//...
var post = _.extend(postAttributes, {
userId: user._id,
author: user.username,
submitted: new Date(),
commentsCount: 0
});
var postId = Posts.insert(post);
//...
/
/
.
lib collections posts js
Ensuite nous mettons à jour le
commentsCount
'
nouveau commentaire en utilisant l op
é
num
rique de un
):
é
'
é
qui s y rapporte lorsque nous cr
rateur Mongo
$inc
(
qui incr
é
ons un
mente un champ
//...
comment = _.extend(commentAttributes, {
userId: user._id,
author: user.username,
submitted: new Date()
});
// update the post with the number of comments
Posts.update(comment.postId, {$inc: {commentsCount: 1}});
return Comments.insert(comment);
//...
/
/
.
lib collections comments js
,
Finalement
nous pouvons simplement supprimer le helper
commentsCount
de
client/templates/posts/post_item.js , puisque le champ est maintenant directement
.
disponible sur le post
Commit 10-5
é
D
.
normalisation du nombre de commentaires dans le post
'
Voir sur GitHub
Lancer l instance
,
Maintenant que les utilisateurs peuvent discuter entre eux
.
nouveaux commentaires
é
impl
,
Et vous savez quoi
menter les notifications pour
é
viter ça
!
'
ce serait dommage qu ils ratent les
le prochain chapitre vous montrera comment
La Dénormalisation
é
D
'
normaliser des donn
, é
d autres termes
é
donn
d
é
é
es veut dire ne pas stocker ces donn
es sous une forme
normalisation veut dire avoir de multiples copies du m
ê
“
”.
normale
En
me morceau de
.
e dans de multiples endroits
,
Dans le dernier chapitre
'
l objet
‘ ’
post
pour
vue de la mod
é
nous avons d
'
é
é
é
le total du nombre de commentaires dans
.
é
lisation des donn
é ,
es
é
les consid
normalis
viter d avoir à constamment charger tous les commentaires
compter les commentaires ad
ô
).
(
t
en omettant
rations de performance
normaliser est souvent synonyme de travail suppl
,
notre exemple
'
è
chaque fois que l on ajoute ou enl
'
é
rappeler de mettre à jour l article concern
(
)
total des commentaires
.
reste juste
'
'
é
,
'
l approche classique a
é
mentaire pour le d
ve un commentaire
,
.
veloppeur
il faudra
pour s assurer que le champs
é
Dans
galement se
commentsCount
é
C est exactement pour cela que les bases de donn
'
es
œ .
telles que MySQL voient cette approche d un mauvais
Cependant
'
D un point de
ceci est redondant puisque nous pourrions plut
quats à tout moment pour calculer cette valeur
é
D
10.5
SIDEBAR
il
é
é
galement ses inconv
:
nients
éé
sans une propri
t
commentsCount , nous devrions envoyer tous les commentaires en permanence vers le serveur
,
afin de pouvoir les compter
nous
é
viter tout cela
é
ce que nous faisions au d
.
part
é
La d
normalisation permet de
.
Une Publication Spéciale
é
Il serait possible de cr
commentaires qui nous int
'
'
(
é
ressent
que l on peut voir actuellement
Mais il conviendrait d
é
er une publication sp
'é
,
ê
en utilisant des requ
é
é
éé
s cr
'
par exemple le total des commentaires d articles
tudier si la complexit
l emporterait sur les difficult
ciale qui envoie uniquement le total des
'
tes d agr
'
é
d un tel code de publication
é
es par la d
…
normalisation
).
gation sur le serveur
û,
Bien s
'
l int
é
r
é
de telles consid
é
grit
des donn
'
:
rations sont propre à l application
'
é
es est d importance capitale
est bien plus important et de priorit
é
é
bien plus
si vous
,
alors
é
lev
é
ù
crivez du code o
é
é
viter les inconsistances de donn
e que des gains de performance
es
.
Intégrer des Documents ou Utiliser des Collections Multiples
Si vous
ê
,
tes familier avec Mongo
-ê
vous avez peut
tre
éé
t
éé
surpris de voir que nous avons cr
:
une seconde collection uniquement pour les commentaires
commentaires dans une liste dans le
'
è
Il s av
' '?
post
'
.
.
collection find
()). '
'
et
est tr
Par exemple
deny
:
'
è
s efficace lorsque l on it
ê
'
'
é
l on op
è
.
,
fonctionnent au niveau du document
rait au niveau du
le Protocole de Donn
niveau du document
,
article
,
' ’.
é
–
é
es Distribu
es
( )
DDP
è
op
cela voudrait dire que si
è
le serveur enverrait la liste compl
.
,
Par exemple
nous assurant ainsi que toute
chose qui serait plus complexe si
re au niveau des attributs au plus au
'
comments était une propriété d un
te des commentaires mis à jour pour cet
é.
'
é
è
Mongo sugg
û
'
re d int
'
, ù
o
'
l acc
è
'
ler au niveau des
,
on
.
'
é
grer les documents dans l ordre pour r
é
cup
.
rer
,
Cependant
compte l architecture de Meteor
client
ô
aliser à moins que les commentaires ne soient dans leur
é
é
teuses pour les r
'
sultat de
si l on voulait paginer les commentaires d un article
trouverait cela difficile à r
propre collection
é
le r
re sur un tableau d objets dans
Les publications et souscriptions sont beaucoup plus faciles à contr
documents
(
post
article vers chaque client connect
co
re sur un curseur
me lorsque l on it
modification de commentaire individuel soit correcte
4.
grer les
Il n en est pas de m
un plus gros document
2. allow
è
{{#each}}
La fonction
3.
é
pourquoi ne pas juste int
re que de nombreux outils que Meteor nous fournis marchent bien mieux lorsqu ils
fonctionnent au niveau d une collection
1.
:
ê
ceci rev
'
ê
duire le nombre de requ
'
tes
t moins d importance lorsque l on prend en
'
la plupart du temps l on recherchera les commentaires sur le
s à la base de donn
é
es est essentiellement gratuite
.
Les Inconvénients de la Dénormalisation
é
On peut facilement d
'
é
fendre le fait qu il ne faille pas d
é
examiner les arguments contre la d
,
normalisation
.
You Should Never Use MongoDB par Sarah Mei
é .
normaliser ses donn
es
Pour
nous vous recommandons Why
Les Notifications
11
,
Maintenant que les utilisateurs peuvent commenter les articles de chacun
'
il serait bien de les
é.
avertir qu une conversation a commenc
Pour ce faire
,
'
'
'
nous notifierons à l auteur de l article qu il y a eu un commentaire
.
,
et nous lui
fournirons un lien pour voir le commentaire
'
é
C est sur ce type de fonctionnalit
é
par d
'
,
faut
que Meteor resplendit
:
.
é
nous afficherons ces notifications instantan
'
î
d attendre que l utilisateur rafra chisse la page ou v
é
é
parce que Meteor est en temps r
ment
'
Nous n avons pas besoin
,
rifie par un quelconque moyen
î
pouvons simplement faire appara tre de nouvelles notifications sans m
é
sp
el
ê
é
me
nous
crire de code
.
cial
Créer des Notifications
Nous allons cr
'
é
les notifications pourront
'
ê
tre
é
é
é
ons notre collection
é
qui ins
'
'
,
Dans le future
é
tendues pour couvrir beaucoup d autres sc
l instant ce sera suffisant pour garder les utilisateurs inform
Cr
.
er une notification quand quelqu un commente sur vos articles
,
narios
s de ce qu il se passe
mais pour
.
'
Notifications , ainsi qu une fonction createCommentNotification
rera une notification correspondante pour chaque nouveau commentaire sur un de
.
vos articles
,
Puisque nous allons mettre à jour les notifications depuis le client
que notre appel
'
allow
est blind
é.
'
l utilisateur qui lance l appel
é .
modifi
é
Nous allons donc v
update
poss
è
rifier que
nous devons nous assurer
:
'ê
de la notification qui est en train d
e
'
.
l utilisateur essaie seulement de mettre à jour un seul champ
é é read
ce seul champ est la propri
t
de nos notifications
.
tre
Notifications = new Mongo.Collection('notifications');
Notifications.allow({
update: function(userId, doc, fieldNames) {
return ownsDocument(userId, doc) &&
fieldNames.length === 1 && fieldNames[0] === 'read';
}
});
createCommentNotification = function(comment) {
var post = Posts.findOne(comment.postId);
if (comment.userId !== post.userId) {
Notifications.insert({
userId: post.userId,
postId: post._id,
commentId: comment._id,
commenterName: comment.author,
read: false
});
}
};
/
/
.
lib collections notifications js
Comme les articles ou commentaires
.
client et serveur
'
,
Notifications
cette collection
,
'
nous autorisons
é
,
galement les mises à jours
é
d habitude de bien limiter les permissions aux propres donn
é
galement cr
, é
commente
d
é
Nous cr
é
compl
éé
ê
é
tre notifi
,
à ce moment
jà des commentaires dans une m
é
.
thode pour appeler notre fonction
Comments.insert(comment);
’ _id
notre fonction
'
en s assurant comme
'
.
es de l utilisateur
'
par
t
è
et ins
ôé
thode c
é
ter cette m
sauvegarder l
t
'
une simple fonction qui surveille l article que l utilisateur
termine qui devrait
é
ons d
ôé
e c
Comme nous avons besoin de mettre à jour les notifications une fois que
l utilisateur les a vues
Nous avons
é
sera partag
.
re une nouvelle notification
serveur
,
donc nous pouvons juste
Nous remplacerons
return
comment._id = Comments.insert(comment)
du commentaire nouvellement cr
createCommentNotification :
éé
,
dans une variable
afin de
puis appellerons
Comments = new Mongo.Collection('comments');
Meteor.methods({
commentInsert: function(commentAttributes) {
//...
comment = _.extend(commentAttributes, {
userId: user._id,
author: user.username,
submitted: new Date()
});
// met à jour le post avec le nombre de commentaires
Posts.update(comment.postId, {$inc: {commentsCount: 1}});
// crée le commentaire et enregistre l'id
comment._id = Comments.insert(comment);
// crée maintenant une notification, informant l'utilisateur qu'il y a e
u un commentaire
createCommentNotification(comment);
return comment._id;
}
});
/
/
.
lib collections comments js
Publions
é
galement les notifications
:
Meteor.publish('posts', function() {
return Posts.find();
});
Meteor.publish('comments', function(postId) {
check(postId, String);
return Comments.find({postId: postId});
});
Meteor.publish('notifications', function() {
return Notifications.find();
});
/
.
server publications js
Et souscrivons sur le client
:
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() {
return [Meteor.subscribe('posts'), Meteor.subscribe('notifications')]
}
});
/
.
lib router js
'
Commit 11-1
Ajout d une collection basique de notifications
Voir sur GitHub
.
'
Lancer l instance
Affichage des notifications
' -ê
Maintenant nous pouvons continuer et ajouter une liste de notifications à l en t
.
te
<template name="header">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="col
lapse" data-target="#navigation">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{pathFor 'postsList'}}">Microscope</a>
</div>
<div class="collapse navbar-collapse" id="navigation">
<ul class="nav navbar-nav">
{{#if currentUser}}
<li>
<a href="{{pathFor 'postSubmit'}}">Submit Post</a>
</li>
<li class="dropdown">
{{> notifications}}
</li>
{{/if}}
</ul>
<ul class="nav navbar-nav navbar-right">
{{> loginButtons}}
</ul>
</div>
</nav>
</template>
/
/
/
.
client templates includes header html
é
Et cr
è
er les mod
fichier
les de
notifications
)
notifications.html :
et
notificationItem
(
ê
ils partageront un m
me
<template name="notifications">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Notifications
{{#if notificationCount}}
<span class="badge badge-inverse">{{notificationCount}}</span>
{{/if}}
<b class="caret"></b>
</a>
<ul class="notification dropdown-menu">
{{#if notificationCount}}
{{#each notifications}}
{{> notificationItem}}
{{/each}}
{{else}}
<li><span>No Notifications</span></li>
{{/if}}
</ul>
</template>
<template name="notificationItem">
<li>
<a href="{{notificationPostPath}}">
<strong>{{commenterName}}</strong> a commenté votre article
</a>
</li>
</template>
/
/
/
.
client templates notifications notifications html
'
é
Nous pouvons voir que l id
éé
t
é,
comment
,
Ensuite
'
'
é.
et le nom de l utilisateur qui l a comment
nous avons besoin de nous assurer que nous s
notifications dans notre helper
'
'
e est de fournir dans chaque notification un lien vers l article qui a
,
é
lectionnons la bonne liste de
et mettons à jour les notifications comme
.
l utilisateur clique sur le lien vers lequel elles pointent
“ ”
lues
quand
Template.notifications.helpers({
notifications: function() {
return Notifications.find({userId: Meteor.userId(), read: false});
},
notificationCount: function(){
return Notifications.find({userId: Meteor.userId(), read: false}).count(
);
}
});
Template.notificationItem.helpers({
notificationPostPath: function() {
return Router.routes.postPage.path({_id: this.postId});
}
});
Template.notificationItem.events({
'click a': function() {
Notifications.update(this._id, {$set: {read: true}});
}
});
/
/
/
.
client templates notifications notifications js
Commit 11-2
' -ê
Afficher des notifications dans l en t
'
Voir sur GitHub
Lancer l instance
é
Vous pouvez penser que les notifications ne sont pas si diff
è
leur structure est tr
collection client
/
.
s similaire
navigateurs et des diff
-
,
utilisateur
principal
(
:
é
anmoins une diff
é .
serveur synchronis
e
,
rents appareils
ouvrez un deuxi
è
chose comme ça
:
nous avons cr
éé
une
î
survivront au rafra chissement des
(
),
disons Firefox
et commentez sur un article que vous avez cr
é
'
et c est vrai que
.
me navigateur
que vous avez laiss
é:
rence cl
,
,
me compte utilisateur
é
rentes des erreurs
Cela signifie que nos notifications sont persistantes et
ê
tant que nous gardons le m
Essayez le
é
Il y a n
.
te
).
ouvert dans Chrome
éé
cr
é
ez un nouveau compte
avec votre compte utilisateur
î
Vous devriez voir appara tre quelque
Afficher des notifications.
Contrôler l'accès aux notifications
.
Les notifications fonctionnent bien
,
Cependant
è
il y a un petit probl
me
:
nos notifications sont
.
publiques
è
Si vous avez encore votre deuxi
dans une console navigateur
,
me navigateur ouvert
’
é
essayez d ex
:
cuter le code suivant
❯
1
Notifications.find().count();
Console du navigateur
Ce nouvel utilisateur
'
(
notification qu il voit dans la collection
.
)
é
celui qui a comment
.
ne devrait pas avoir de notifications
Notifications
La
appartient en fait à notre utilisateur
original
è
En marge de ces potentiels probl
é,
mes de confidentialit
nous ne pouvons pas nous permettre
'
é
d avoir toutes les notifications des utilisateurs charg
.
utilisateurs
,
Sur un assez gros site
î
é
cela pourrait surcharger la m
é
navigateur et faire appara tre des s
rieux probl
è
pour sp
é
moire disponible du
mes de performance
è
.
me avec les publications
Nous corrigeons ce probl
es dans tous les navigateurs des autres
.
Nous pouvons utiliser nos publications
é é
cifier pr
cis
ment quelle partie de notre collection nous voulons partager dans
.
chaque navigateur
,
Pour accomplir cela
publication de
nous avons besoin de retourner un curseur diff
é
rent dans notre
Notifications.find() . Plus exactement, nous voulons retourner un curseur
'
.
qui correspond aux notifications de l utilisateur courant
,
Faire cela est assez direct
disponible via
puisqu
this.userdId :
’
publish
une fonction
a l
’ id
'
de l utilisateur courant
Meteor.publish('notifications', function() {
return Notifications.find({userId: this.userId, read: false});
});
/
.
server publications js
Commit 11-3
…
Synchroniser uniquement les notifications pertinentes pou
'
Voir sur GitHub
Maintenant
,
é
si nous v
ê
rifions dans nos deux fen
é
collections de notifications diff
❯
1
Lancer l instance
rentes
:
Notifications.find().count();
tres de navigateur
,
nous devrions voir deux
Console du navigateur
❯
0
utilisateur
)
1
Notifications.find().count();
Console du navigateur
En fait
,
(
utilisateur
)
2
ê
la liste de Notifications devrait m
é
d
(
connectiez de votre application
.
me changer selon que vous vous authentifiez et vous
é
Tout cela parce que les publications sont republi
automatiquement quand le compte utilisateur change
.
Notre application devient de plus en plus fonctionnelle
'
es
,
et à mesure que des utilisateurs
'
s inscrivent et ajoutent des liens nous courons le risque de finir avec une page d accueil sans
.
fin
Nous allons nous occuper de ça dans le prochain chapitre en impl
.
pagination
é
mentant une
Réactivité Avancée
'
11.5
SIDEBAR
'é
Il est rare d avoir besoin d
-
crire du code de traçage vous m
ê
me
,
mais il est assur
é
de le comprendre pour comprendre la façon dont le processus de r
fonctionne
é
ment utile
é
solution de d
pendance
.
'
'
Imaginez que nous voulions tracer combien d amis Facebook de l utilisateur courant ont
“
”
é
aim
é
les d
'
,
l API
.
chaque article sur Microscope
'
'
,
tails de l authentification de l utilisateur avec Facebook
'
et fait l analyse des donn
ôé
asynchrone c
t
é
é
Partons du principe que nous avons d
.
es pertinentes
é
é
fait les appels appropri
s vers
“'
j aime
”, getFacebookLikeCount(user,
'
'
é
La chose importante à retenir au sujet d une telle fonction est qu elle est vraiment non r
é .
et non temps r
ê
Elle fera une requ
el
'
, é
te HTTP vers Facebook
,
rendra disponible à l application via un rappel asynchrone
-
ê
une nouvelle fois par elle m
,
Pour corriger cela
r
é
cup
'
es
active
et les
é
mais la fonction ne s ex
,
-
é
é ,
rera des donn
me quand le compte changera chez Facebook
changera pas quand les donn
sur
Nous avons maintenant une fonction
client qui retourne le nombre de
url, callback) .
jà travaill
cutera pas
et notre UI ne
.
es sous jacentes le feront
é
nous pouvons d
marrer en utilisant
fonction toutes les quelques secondes
setInterval
pour appeler notre
:
currentLikeCount = 0;
Meteor.setInterval(function() {
var postId;
if (Meteor.user() && postId = Session.get('currentPostId')) {
getFacebookLikeCount(Meteor.user(), Posts.find(postId).url,
function(err, count) {
if (!err)
currentLikeCount = count;
});
}
}, 5 * 1000);
ù
Quel que soit le moment o
é
nous v
rifions cette variable
currentLikeCount , nous pouvons
'
.
nous attendre à avoir un nombre correct avec une marge d erreur de cinq secondes
Nous
:
pouvons utiliser cette variable dans un helper comme suit
Template.postItem.likeCount = function() {
return currentLikeCount;
}
,
Cependant
rien ne dit à notre template de se recharger quand
é
Bien que la variable soit maintenant pseudo temps r
'
elle n est pas r
'é
de l
.
change
'
-
el du fait qu elle change par elle m
ê
,
me
é
active donc elle ne peut pas tout à fait communiquer proprement avec le reste
è
cosyst
currentLikeCount
.
me Meteor
Réactivité de la surveillance : Computations (Calculs)
é
La r
é
activit
de Meteor est contr
ôé
l
,
é
e par des d
pendances
é
des structures de donn
es qui
.
surveillent un ensemble de calculs
'
éé
Comme nous l avons vu dans un pr
code qui utilise des donn
le template
é
es r
c
é
.
actives
é
dent apart
é
sur la r
,
Dans notre cas
é,
activit
un calcul a
un calcul est une section de
éé
t
éé
implicitement cr
pour
postItem , chaque helper de ce gestionnaire de template a sa propre partie
.
calculs
Vous pouvez penser au calcul comme à la section de code qui
é
donn
é
es r
.
actives
)
Quand la donn
'
é
e change
,
“'
”
s occupe
de la source de
é
ce sera ce calcul qui en sera inform
invalidate() , et c est le calcul qui décide si quelque chose doit être fait.
(
via
Transformer une Variable en une Fonction Réactive
Pour transformer notre variable
currentLikeCount
'
é
en source de donn
é
avons besoin de surveiller tous les calculs qui l utilisent dans une d
de la transformer de variable à fonction
(
qui retourne une valeur
):
es r
é
actives
.
pendance
,
nous
Cela requiert
var _currentLikeCount = 0;
var _currentLikeCountListeners = new Tracker.Dependency();
currentLikeCount = function() {
_currentLikeCountListeners.depend();
return _currentLikeCount;
}
Meteor.setInterval(function() {
var postId;
if (Meteor.user() && postId = Session.get('currentPostId')) {
getFacebookLikeCount(Meteor.user(), Posts.find(postId),
function(err, count) {
if (!err && count !== _currentLikeCount) {
_currentLikeCount = count;
_currentLikeCountListeners.changed();
}
});
}
}, 5 * 1000);
é
Nous avons mis en place une d
_currentLikeCountListeners , qui surveille tous
currentLikeCount()
les calculs dans lesquels
_currentLikeCount
pendance
change
,
a
éé
t
é.
utilis
changed()
nous appelons la fonction
qui invalide tous les calculs surveill
Quand la valeur de
é
sur cette d
é.
s
Ces calculs peuvent ensuite continuer et traiter le changement au cas par cas
Si cela vous semble
é
r
active
simple
'
(
,
ê
é
tre une approche un peu r
vous avez raison
,
'
.
é
barbative pour une simple source de donn
é é
et Meteor fournit des outils int
'
gr
s pour rendre ça un peu plus
,
tout comme vous n avez pas besoin d utiliser des calculs directement
).
d habitude des autoruns
exactement ce que notre
-
é reactive-var
Il y a un paquet plate forme appel
currentLikeCount()
.
fonction fait
'
vous utilisez
qui fait
Si nous l ajoutons
meteor add reactive-var
'
,
pendance
Nous pouvons l utiliser pour simplifier notre code un petit peu
:
:
es
var currentLikeCount = new ReactiveVar();
Meteor.setInterval(function() {
var postId;
if (Meteor.user() && postId = Session.get('currentPostId')) {
getFacebookLikeCount(Meteor.user(), Posts.find(postId),
function(err, count) {
if (!err) {
currentLikeCount.set(count);
}
});
}
}, 5 * 1000);
Maintenant
,
'
,
pour l utiliser
cela fonctionnera comme avant
ô é
fournit un entrep
aussi utile
t r
currentLikeCount.get()
nous appellerons
-
é
actif cl
.
.
-
dans notre helper et
reactive-dict , qui
Il y a aussi un autre paquet plate forme
valeur
(
presque exactement comme
)
Session , qui peut être
Comparer Tracker à Angular
Angular est une biblioth
gens de Google
.
Il est int
'
è
é
que de rendu r
é
,
Meteor à celle d Angular
).
calculs
'
, é
t
client seulement
-
car celles ci sont assez diff
é
é
é
s par des sources de donn
'
é
é.
é é
n
es
“é
r
é
-
Dans Angular
,
la r
é
activit
é
é
activit
”(
fonctions
é
)
qui
es informent
invalidate() . Notez
é,
es ont chang
'
é
la source de donn
é
.
é,
cutent habituellement quand ils sont invalid
.
s
vous
Tout ceci nous donne un haut
é.
ôé
est contr
l
es
clencher une invalidation pour d autres raisons
pouvez les configurer pour se comporter comme vous le voulez
le sur la r
actives
'
é
cider de d
bien que les calculs se re ex
ô
s computations
Donc les sources de donn
ralement quand les donn
é
pourrait potentiellement d
niveau de contr
é
pendances quand elles ont besoin d appeler
que bien que cela se passe g
pendance de
.
le de Meteor utilise des blocs de code appel
Ces calculs sont traqu
par les bonnes
rentes
è
explicitement toutes ses d
,
é
velopp
é
prennent soin de les invalider quand c est appropri
De plus
d
ressant de comparer l approche de surveillance de d
Nous avons vu que le mod
(
ôé
actif c
'
e par l objet
scope . Un scope peut être imaginé
comme un objet JavaScript simple avec plusieurs m
é
Quand vous voulez d
é
é
thodes sp
'
,
pendre activement d une valeur dans un scope
'
scope.$watch , en fournissant l expression qui vous intéresse
é
qui vous int
'
)
resse
ciales
'
é
et une fonction listener qui s ex
.
.
vous appelez
(' --
c est à dire la partie du scope
cutera à chaque fois que la valeur de
l expression change
De retour sur notre exemple Facebook
,
é
nous
cririons
:
$rootScope.$watch('currentLikeCount', function(likeCount) {
console.log('Current like count is ' + likeCount);
});
û,
Bien s
'
r
,
tout comme vous ne mettez que rarement en place des calculs dans Meteor
$watch
n appelez pas souvent
{{expressions}}
et les
é
de r
explicitement dans Angular puisque les directives
'
vous
ng-model
configurent automatiquement des watches qui ensuite s occupent
.
actualiser la page
Quand ce type de valeur r
é
,
chaque watcher du scope
'
é, scope.$apply()
active a chang
doit
ê
é.
tre appel
Ceci r
éé
value
mais appelle seulement la fonction listener des veilleurs pour qui la
é.
valeur de l expression a chang
scope.$apply()
,
scope
éé
r
est similaire à
ô
plut
é.
valu
s
ô
t que vous donner le contr
Ceci dit
,
é
ce l
tre r
éé
le de dire pr
é é
cis
ment quels listeners doivent
'
ô
ger manque de contr
intelligent et efficace dans la mani
ê
'
dependency.changed() , excepté qu il agit au niveau du
è
é
re dont il d
termine pr
é é
cis
'
é ê
le donne à Angular l habilit
d
ê
tre
tre vraiment
ment quels listeners doivent
é.
valu
s
,
Avec Angular
notre code de fonction
getFacebookLikeCount()
devrait ressembler à ça
:
Meteor.setInterval(function() {
getFacebookLikeCount(Meteor.user(), Posts.find(postId),
function(err, count) {
if (!err) {
$rootScope.currentLikeCount = count;
$rootScope.$apply();
}
});
}, 5 * 1000);
,
Certes
'
é é
Meteor s occupe du gros du travail pour nous et nous laisse b
sans trop de travail de notre part
.
,
Mais heureusement
n
é
ficier de la r
’
é
apprendre ces pratiques s av
.
si vous avez besoin de pousser les choses un peu plus loin
é
activit
rera utile
La Pagination
12
Les choses semblent bien avec Microscope
,
è
et nous pouvons nous attendre à un succ
s quand
.
il va sortir pour tout le monde
Donc nous devrions probablement r
é é
fl
chir un peu à propos de la cons
performances du nombre de nouveaux articles qui vont
son envol
!
ê
é
tre entr
é
quence sur les
s dans le site au moment de
éé
Nous avons pr
-
c
demment parl
sous ensemble des donn
é
ôé
de comment une collection c
é
,
es du serveur
et nous avons m
t
ê
client peut contenir un
me appris à r
é
aliser cela pour nos
.
collections de notifications et de commentaires
À pr
é
,
sent
é.
connect
s
Éventuellement
é
Pour r
'
,
nous publions encore tous nos articles d un seul coup
,
soudre cela
,
é,
si des milliers de liens sont post
s
à tous les utilisateurs
é
ceci deviendra probl
.
nous avons besoin de paginer nos articles
Ajouter plus d'articles
è
Premi
,
rement
dans nos donn
cette pagination ait un sens
:
é
es de pr
-
é
,
installation
'
.
matique
chargeons assez d articles pour que
// Fixture data
if (Posts.find().count() === 0) {
//...
Posts.insert({
title: 'The Meteor Book',
userId: tom._id,
author: tom.profile.name,
url: 'http://themeteorbook.com',
submitted: new Date(now - 12 * 3600 * 1000),
commentsCount: 0
});
}
for (var i = 0; i < 10; i++) {
Posts.insert({
title: 'Test post #' + i,
author: sacha.profile.name,
userId: sacha._id,
url: 'http://google.com/?q=test-' + i,
submitted: new Date(now - i * 3600 * 1000),
commentsCount: 0
});
}
/
.
server fixtures js
è
Apr
é
s avoir ex
comme ça
:
cut
é meteor reset
é
et relanc
,
votre appli
vous devriez obtenir quelque chose
Afficher des données factices.
'
Commit 12-1
'
…
é
Ajout d assez d articles pour que la pagination soit n
ce
'
Voir sur GitHub
Lancer l instance
Pagination infinie
é
Nous allons impl
menter une pagination de style
è
que nous voulons premi
'
”
plus d articles
,
liste
,
rement afficher
.
inscrit en bas
, 10
disons
.
et ainsi de suite ad infinitum
'é
articles à l
10
,
cran
“
avec un lien
charger
é
articles suppl
'
é
tre repr
'
Ce que nous voulons dire par là c est
mentaires dans la
ô
Cela signifie que nous pouvons contr
è
'é
”.
infini
Cliquer sur le lien affichera
pagination entier avec un simple param
l
“
è
ler notre syst
me de
sentant le nombre d articles à afficher à
.
cran
'
'
'
.
sache combien d articles envoyer au client
publication
posts
,
dans le routeur
'
è
Maintenant nous allons avoir besoin d un moyen d indiquer au serveur ce param
tre afin qu il
é
Il se trouve que nous nous abonnons d
jà à la
é
donc nous allons profiter de ça et laisser le routeur g
rer
.
notre pagination
La façon la plus facile de configurer cela est simplement de faire du param
'
d articles partie int
é
grante du chemin
,
è
nous donnant des URLs de la forme
'
'
tre de limitation
'
http://localhost:3000/25 . Un autre bon côté d utiliser l URL plutôt que d autres méthodes
25
est que si vous affichez
vous verrez toujours
25
é .
articles une fois la page charg
Afin de faire ça proprement
.
abonnons aux articles
,
articles et que vous recharger la page dans le navigateur par erreur
,
e
nous allons avoir besoin de changer la façon dont nous nous
'
,
Juste comme nous l avons fait dans le chapitre Commentaires
é
allons avoir besoin de d
'
nous
placer notre code de l abonnement du niveau routeur au niveau
.
route
-ê
Tout ça est peut
,
tre un peu beaucoup à comprendre en une seule fois
mais cela deviendra
.
plus clair avec le code
è
Premi
,
rement
nous arr
'
ê
terons l abonnement à la publication
posts
dans le bloc
Routeur.configure() . Supprimez juste Meteor.suscribe('posts') , en laissant seulement
'
l abonnement aux
notifications :
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() {
return [Meteor.subscribe('notifications')]
}
});
/
.
lib router js
è
Nous ajouterons un param
è
du param
tre
'
postsLimit
tre signifie que c est optionnel
.
.
au chemin de la route
Ajouter un
?
apr
è
s le nom
Donc cette route ne correspondra pas seulement à
http://localhost:3000/50 , mais également au simple et ancien http://localhost:3000 .
//...
Router.route('/:postsLimit?', {
name: 'postsList',
});
//...
/
.
lib router js
'
'
C est important de noter qu un chemin de la forme
.
chemins possibles
Chaque route sera analys
avec le chemin courant
,
'
En d autres mots
,
'
e successivement pour voir si elle correspond
cificit
é é
d
croissante
.
é
les routes qui ciblent des routes plus sp
viendraient en premi
correspondra à tous les
nous avons besoin de nous assurer que nous organisons nos routes
é
dans un ordre de sp
é
/:parameter?
è ,
re
et notre route
postsList
cifiques comme
é
serait d
é
plac
/posts/:_id
e en bas du groupe de
.
routes vu qu elle correspond pratiquement avec tout
'
Il est maintenant temps d aborder le dur probl
é .
donn
es
é
Nous avons besoin de g
'
ù
rer le cas o
é
donc nous l assignerons à une valeur par d
'
è
me de s abonner et trouver les bonnes
è
le param
.
faut
tre
postsLimit
Nous utiliserons
.
“5”
'
n est pas pr
é
,
sent
pour nous donner
vraiment assez de place pour jouer avec les paginations
//...
Router.route('/:postsLimit?', {
name: 'postsList',
waitOn: function() {
var limit = parseInt(this.params.postsLimit) || 5;
return Meteor.subscribe('posts', {sort: {submitted: -1}, limit: limit});
}
});
//...
/
.
lib router js
Vous noterez que nous passons maintenant un objet JavaScript
})
postsLimit
è
param
tre
avec le nom de notre publication
options
'
pour l expression de
ôé
modifications dans notre code c
t
serveur pour impl
é
menter ça
Meteor.publish('notifications', function() {
return Notifications.find({userId: this.userId});
});
.
{
-}
: 1,
submitted
:
limit
Posts.find() côté serveur. Faisons quelques
Meteor.publish('comments', function(postId) {
check(postId, String);
return Comments.find({postId: postId});
});
/
:
sort
posts . Cet objet servira au même titre que le
Meteor.publish('posts', function(options) {
check(options, {
sort: Object,
limit: Number
});
return Posts.find({}, options);
});
server publications js
({
:
Passer des paramètres
'
Notre code de publications est effectivement en train de dire au serveur qu il peut
é
faire confiance à tout objet JavaScript envoy
postsLimit}
)
par le client
'
options
pour servir comme les
(
, {limit:
dans notre cas
d expression de
'
find() . Ceci rend
possible pour les utilisateurs de soumettre des options qu ils aiment via la console du
.
navigateur
,
Dans notre cas
é
est r
'
,
c est relativement anodin
é
ordonner les articles diff
,
remment
).
mettre en place en premier lieu
'
vu que tout ce qu un utilisateur peut faire
ou changer la limite
,
en utilisant
check()
passer en douce des options suppl
certains cas exposer des donn
é
Malgr
,
tout
un pattern plus s
-
individuels eux m
ô
le contr
mentaires
es priv
é
é
curis
'
el devrait
é
es
).
pourrait
(
comme
ê
,
mes au lieu de l objet entier
é :
!
é
nous savons que les utilisateurs ne peuvent pas
é
é
ê
le de nos donn
ce que nous voulons
En revanche une appli du monde r
probablement avoir besoin de limiter les limites
Heureusement
(
fields , qui pourrait dans
tre de passer les param
è
tres
pour nous assurer que nous gardons
es
Meteor.publish('posts', function(sort, limit) {
return Posts.find({}, {sort: sort, limit: limit});
});
é
Maintenant que nous nous sommes abonn
mettre le contexte de donn
é
es au m
ê
.
me endroit
pattern et feront en sorte que la fonction
.
simplement retourner un curseur
nous appellerons
s au niveau de la route
data
'
é
éé
l
,
,
é
Nous d
éé
vierons un peu de notre pr
c
dent
Ceci nous laisse cr
é
é
er un contexte de donn
é,
es nomm
que
posts .
rieur du template
ment
cela aurait du sens de
retourne un objet JavaScript au lieu de
'
'ê
Ce que cela signifie est simplement qu au lieu d
l int
,
é
notre contexte de donn
le code devrait
ê
tre familier
:
tre implicitement disponible comme
es sera disponible à
this
posts . A part ce petit
à
//...
Router.route('/:postsLimit?', {
name: 'postsList',
waitOn: function() {
var limit = parseInt(this.params.postsLimit) || 5;
return Meteor.subscribe('posts', {sort: {submitted: -1}, limit: limit});
},
data: function() {
var limit = parseInt(this.params.postsLimit) || 5;
return {
posts: Posts.find({}, {sort: {submitted: -1}, limit: limit})
};
}
});
//...
/
.
lib router js
é
Et puisque que nous avons mis le contexte de donn
é
maintenant nous d
posts_list.js
é
é
é
notre contexte de donn
es
,
capitulons
(
posts
é
ê
le m
me pas besoin de toucher au template
Voici à quoi notre nouveau code am
posts
,
nous pouvons
dans le fichier
.
ê
nous n avons m
R
me du template helper
et supprimer le contenu de ce fichier
Nous avons nomm
'
è
barrasser sans probl
es au niveau des routes
é
lior
postsList
de
),
me nom que le helper
!
router.js
ressemble
:
donc
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() {
return [Meteor.subscribe('notifications')]
}
});
Router.route('/posts/:_id', {
name: 'postPage',
waitOn: function() {
return Meteor.subscribe('comments', this.params._id);
},
data: function() { return Posts.findOne(this.params._id); }
});
Router.route('/posts/:_id/edit', {
name: 'postEdit',
data: function() { return Posts.findOne(this.params._id); }
});
Router.route('/submit', {name: 'postSubmit'});
Router.route('/:postsLimit?', {
name: 'postsList',
waitOn: function() {
var limit = parseInt(this.params.postsLimit) || 5;
return Meteor.subscribe('posts', {sort: {submitted: -1}, limit: limit});
},
data: function() {
var limit = parseInt(this.params.postsLimit) || 5;
return {
posts: Posts.find({}, {sort: {submitted: -1}, limit: limit})
};
}
});
var requireLogin = function() {
if (! Meteor.user()) {
if (Meteor.loggingIn()) {
this.render(this.loadingTemplate);
} else {
this.render('accessDenied');
}
} else {
this.next();
}
}
Router.onBeforeAction('dataNotFound', {only: 'postPage'});
Router.onBeforeAction(requireLogin, {only: 'postSubmit'});
/
.
lib router js
Commit 12-2
é
Am
'
Voir sur GitHub
'
Lancer l instance
è
Essayons notre tout nouveau syst
'
.
liorer la route postsList pour avoir une limite
.
me de pagination
é
Nous avons maintenant la possibilit
'
d afficher un nombre arbitraire d articles sur la page d accueil simplement en changeant le
è
param
'
tre dans l URL
.
,
Par exemple
'
é
essayez d acc
verrez maintenant quelque chose comme ça
:
der à
Contrôler le nombre d'articles sur la page d'accueil.
http://localhost:3000/3 . Vous
Pourquoi pas des pages ?
-
Pourquoi utilisons nous une approche de
10
pages successives avec
é
r
sultats de recherche
.
? '
“
pagination infinie
,
û
articles sur chaque
C est actuellement d
”
au lieu de montrer des
comme ce que Google fait pour ses
-é
au paradigme temps r
é
el embrass
par Meteor
Posts
Imaginons que nous paginons notre collection
,
pagination de Google
--
et que nous sommes à la page
Que se passe t il si un utilisateur supprime un des
é
Étant donn
.
pourrait changer
'
'
11
'
10
L article
pendant que l article
'
-é
que notre application est temps r
deviendrait l article
2,
qui affiche les articles
10 é é
pr
,
9,
el
en utilisant le pattern de
c
dents articles
?
10 20.
à
é
notre ensemble de donn
es
î
et dispara trait de notre vue
serait maintenant dans le cr
é
neau
.
é
Le r
,
sultat final serait que
.
l utilisateur verrait soudainement ses articles changer sans raisons apparentes
ê
M
é
é
me si nous tol
traditionnelle est
galement difficile à impl
Revenons à notre exemple pr
collection
'
é
rions cette bizarrerie dans l exp
éé
c
.
dent
é
'
l ensemble de donn
Nous publions les articles
?
es c
t
10
é
'
vous avez plus d un abonnement aux articles
,
et ensuite
é.
s
--
Mais que va t il se passer si
ô
comme nous le ferons bient
10 20,
é ôé
.
Disons qu un abonnement demande les articles
articles charg
,
rer tous les articles publi
.
20
Vous ne pouvez
articles sur le serveur
Ceci fonctionne si vous avez seulement un abonnement
Vous avez maintenant
de la
client
Posts.find() côté client pour récup
'
à
comme il y a seulement dix articles en tout dans
Une solution serait simplement de publier ces
40.
10 20
10 20,
ôé
.
é
la pagination
.
à
,
menter pour des raisons techniques
Posts , mais comment trouver ces articles sur le client
pas prendre les articles de
faire un
rience utilisateur
s c
t
à
t
?
et un autre les articles
,
client au total
,
'
'
la pagination traditionnelle n a pas beaucoup de sens
.
lorsqu on travaille avec Meteor
Créer un contrôleur de route
à
avec aucun moyen
de savoir lesquels appartiennent à quel abonnement
Pour toutes ces raisons
30
é
Vous avez not
|| 5;
que nous r
.
deux fois
,
fin du monde
Yourself
:
,
De plus
é é
p
tons la ligne
var limit = parseInt(this.params.postsLimit)
coder en dur le nombre
'
“5” '
é .
n est pas vraiment id
mais comme c est toujours mieux de suivre le principe DRY
Ne vous r
é é
petit peu les choses
é
Nous allons pr
p
.
)
tez pas
,
si vous le pouvez
senter un nouvel aspect de Iron Router
,
é
utilisable dont toutes les routes peuvent h
,
uniquement pour une seule route
é
fonctionnalit
( ’
Don t Repeat
ô
les Contr
é
é
riter
.
'
Maintenant nous allons l utiliser
.
deviendra pratique
Router.route('/:postsLimit?', {
name: 'postsList'
});
.
leur
mais vous verrez dans le prochain chapitre comment cette
//...
/
ô
Un contr
s de routage ensemble dans
PostsListController = RouteController.extend({
template: 'postsList',
increment: 5,
postsLimit: function() {
return parseInt(this.params.postsLimit) || this.increment;
},
findOptions: function() {
return {sort: {submitted: -1}, limit: this.postsLimit()};
},
waitOn: function() {
return Meteor.subscribe('posts', this.findOptions());
},
data: function() {
return {posts: Posts.find({}, this.findOptions())};
}
});
lib router js
.
leurs de Route
//...
//...
'
Ce n est pas la
voyons comment nous pouvons remanier un
de route est simplement un moyen de grouper les fonctionnalit
un paquet r
al
.
Allons y pas à pas
Premi
è
,
rement
nous cr
é
ons notre contr
ô
leur en
RouteController . Puis Nous mettons la propriété template
,
avant
é
é
tape suppl
è,
s
'
juste comme nous l avons fait
t
finissions une nouvelle fonction
,
mentaire
ô
waitOn
et
data
'
).
s en occupe
'
data
de la d
é
ô
leur
.
ô
Si nous avions besoin d utiliser un contr
controller
(
que
postsList , Iron
et notre route
Nous avons donc seulement besoin de
finition de notre route
'
é
except
findOptions .
é PostsListController
et
pu utiliser l option
,
juste comme avant
leur est appel
Router utilisera automatiquement le contr
waitOn
Cela pourrait ressembler à une
.
maintenant elles vont utiliser notre nouvelle fonction
supprimer
et
mais nous en ferons usage plus tard
finissions des fonctions
Puisque notre contr
qui retournera la limite courante
qui retournera un objet options
é
nous d
,
postslimit
.
findOptions
une fonction
Apr
tendant
é é increment .
et ensuite une nouvelle propri
Puis nous d
é
é
(
é
puisque dor
ô
navant le contr
leur avec un autre nom
,
leur
nous aurions
).
nous verrons un exemple de ça dans le prochain chapitre
Commit 12-3
é
Route postsList remani
es dans un contr
Voir sur GitHub
ô
leur de route
.
'
Lancer l instance
Ajouter un lien « Charger plus »
Nous avons une pagination qui fonctionne
'
'
,
.
et notre code est bien fait
é
il n y a aucun moyen d utiliser actuellement cette pagination except
manuellement
.
Ceci ne fait d
é
é
finitivement pas une bonne exp
è
Il y a juste un probl
'
me
en changeant l URL
rience utilisateur
,
donc
.
retournons au travail pour corriger ça
.
Ce que nous voulons faire est assez simple
'
,
bas de notre liste d articles
'
.
qu on clique dessus
cliquer sur
“
é
qui incr
Nous allons ajouter un bouton
'
'
Donc si je suis actuellement sur l URL
”
Charger plus
è
nous am
é
mentera le nombre d articles affich
ne à
“
Charger plus
s par
5
”
en
chaque fois
http://localhost:3000/5 ,
http://localhost:3000/10 . Si vous êtes arrivé
:
,
aussi loin dans le livre
éé
Comme pr
c
'
nous pensons que vous pouvez supporter un peu d arithm
demment
,
.
tique
nous ajouterons notre logique de pagination dans notre route
vous souvenez quand nous avons explicitement nomm
juste utiliser un curseur anonyme
,
seulement passer des curseurs
de notre bouton
é
“
”.
?
,
Bien
'
é
il n y a pas de r
é
notre contexte de donn
gle qui dit que la fonction
ê
n
ô
data
é é
me technique pour g
Vous
es plut
è
donc nous utiliserons la m
.
'
t que
peut
rer l URL
charger plus
//...
PostsListController = RouteController.extend({
template: 'postsList',
increment: 5,
postsLimit: function() {
return parseInt(this.params.postsLimit) || this.increment;
},
findOptions: function() {
return {sort: {submitted: -1}, limit: this.postsLimit()};
},
waitOn: function() {
return Meteor.subscribe('posts', this.findOptions());
},
posts: function() {
return Posts.find({}, this.findOptions());
},
data: function() {
var hasMore = this.posts().count() === this.postsLimit();
var nextPath = this.route.path({postsLimit: this.postsLimit() + this.inc
rement});
return {
posts: this.posts(),
nextPath: hasMore ? nextPath : null
};
}
});
//...
/
.
lib router js
Regardons plus en d
(
é
qui h
è
tre
.
tail la magie du routeur
ô
rite du contr
param
é
leur
postsLimit .
Vous vous souvenez que la route
PostsListController
sur lequel nous travaillons
)
postsList
prend un
this.route.path()
Donc quand nous alimentons
{postsLimit: this.postslimit()
avec
+ this.increment} , nous disons à la route postsList
de construire son propre chemin en
é .
utilisant cet objet JavaScript comme contexte de donn
'
En d autres mots
,
'
ê
c est exactement la m
es
'
'postsList'}} , excepté que nous remplaçons le this
é
donn
{{pathFor
me chose qu utiliser le helper Spacebars
implicite par notre contexte de
é.
es personnalis
'
é
Nous prenons ce chemin et l ajoutons au contexte de donn
'
'
.
seulement s il y a plus d articles à afficher
this.limit()
Nous savons que
,
montrer
qui peut
'
mais
é .
e
,
.
é
ou notre valeur par d
faut
(5) '
si l URL ne
tre
ô é, this.posts é è
'
'
tre la valeur dans l URL courante
è
'
re dont on fait ça est un peu rus
,
retourne le nombre courant d articles que nous aimerions
ê
contient pas de param
D un autre c
è
La mani
es pour notre template
t
r
f
,
re au curseur courant
donc
this.posts.count() réfère au
.
nombre d articles qui sont actuellement dans le curseur
n
Donc ce que nous disons ici est que si nous demandons
'
nous continuerons d afficher le bouton
é
nous r
é
cup
rons moins de
ê
voulons arr
Ceci
é
'
,
de donn
notre syst
é
è
me
es est exactement
”.
charger plus
é
é
cup
n
Mais si nous demandons
n,
rons
et que
n , ça voudra dire que nous avons atteint la limite et que nous
ter d afficher ce bouton
tant dit
“
articles et nous r
é
.
choue dans un cas
;
n . Si cela arrive, le client demandera n
articles et continuera à afficher le bouton
.
“
'
quand le nombre d items dans notre base
”,
charger plus
é
articles et r
' '
é
cup
n
rera
'
inconscient qu il n y a plus d items
restants
'
C est triste
,
'
è
il n y a pas de contournements simples à ce probl
devrons nous contenter de cette impl
'
'
'
donc pour l instant nous
.
mentation moins que parfaite
Tout ce qu il reste à faire est d ajouter le lien
'
- -
é
,
me
“
”
charger plus
'
,
en bas de notre liste d articles
nous assurant de l afficher seulement si nous avons encore des articles à charger
:
en
<template name="postsList">
<div class="posts">
{{#each posts}}
{{> postItem}}
{{/each}}
{{#if nextPath}}
<a class="load-more" href="{{nextPath}}">Load more</a>
{{/if}}
</div>
</template>
/
/
/
_
client templates posts posts
.
list html
'
Voici à quoi votre liste d articles devrait ressembler
:
Le bouton “Charger plus“.
()
nextPath
é
ajout
Commit 12-4
ô
au contr
Voir sur GitHub
é
leur et utilis
'
pour franchir
Lancer l instance
…
Une meilleure expérience utilisateur
,
Notre pagination fonctionne maintenant correctement
bizarrerie
'
,
d articles
'
:
à chaque fois que nous cliquons sur
é
nous sommes envoy
é
l arriv
e des nouvelles donn
«
charger plus
é .
es
Le r
»
s vers le template
'
mais elle souffre d une ennuyeuse
loading
et que le routeur demande plus
pendant que nous attendons
é
sultat est que nous sommes envoy
é
s en haut de la page à
é
chaque fois et nous avons besoin de faire d
filer la page vers le bas pour continuer notre
.
navigation
è
Donc premi
tout
.
,
rement
,
Au lieu de ça
waitOn
nous devrons dire à Iron Router de ne pas
nous d
é
finirons nos abonnements dans un hook
.
Notez que nous ne renvoyons pas cet abonnement dans le hook
normalement avec le hook
'
subscription
c est exactement ce que nous voulons
subscriptions
subscriptions .
(
Le renvoyer
ce qui est fait
.
viter
,
clencherais le hook de chargement global
À la place
é
,
et
nous utilisons simplement le hook
,
finir notre abonnement
de la m
ê
me
onBeforeAction .
Nous passons aussi une variable
éé
'
è
é
d
comme un endroit pratique pour d
façon que pour le hook
l
é
)
'
l abonnement apr
ready
ment de notre contexte de donn
l abonnement au post a termin
é
é .
es
qui se r
éè
f
re à
this.postsSub.ready
comme un
Cela nous permettra de dire au template quand
de charger
.
s
//...
PostsListController = RouteController.extend({
template: 'postsList',
increment: 5,
postsLimit: function() {
return parseInt(this.params.postsLimit) || this.increment;
},
findOptions: function() {
return {sort: {submitted: -1}, limit: this.postsLimit()};
},
subscriptions: function() {
this.postsSub = Meteor.subscribe('posts', this.findOptions());
},
posts: function() {
return Posts.find({}, this.findOptions());
},
data: function() {
var hasMore = this.posts().count() === this.postsLimit();
var nextPath = this.route.path({postsLimit: this.postsLimit() + this.inc
rement});
return {
posts: this.posts(),
ready: this.postsSub.ready,
nextPath: hasMore ? nextPath : null
};
}
});
//...
/
.
lib router js
é
Nous allons ensuite v
rifier dans le template que cette variable
ready
affiche un spinner en
bas de la liste de posts pendant que nous chargeons un nouveau lot de posts
:
<template name="postsList">
<div class="posts">
{{#each posts}}
{{> postItem}}
{{/each}}
{{#if nextPath}}
<a class="load-more" href="{{nextPath}}">Load more</a>
{{else}}
{{#unless ready}}
{{> spinner}}
{{/unless}}
{{/if}}
</div>
</template>
/
/
/
_
client templates posts posts
.
list html
Commit 12-5
é
Avec un spinner pour rendre la pagination plus agr
.
able
'
Voir sur GitHub
Lancer l instance
Accéder à des articles
Nous sommes en train de charger les cinq articles les plus r
--
'
'
é
é
cents par d
passe t il quand quelqu un explore une page d article individuelle
?
,
faut
mais que se
Un template vide.
,
Si vous essayez
vous allez faire face à une erreur
'
«
avons dit au routeur de s abonner à la publication
»
é .
non trouv
posts
Cela semble normal
:
nous
quand il charge la route
postsList , mais nous ne lui avons pas dit quoi faire au sujet de la route postPage .
,
Mais
'
tout ce que nous savons faire c est nous abonner à une liste des
--
é
Comment demande t on au serveur pour un seul article sp
un petit secret ici
:
'
Nous allons vous donner
!
,
é
nous allons simplement cr
er une nouvelle
singlePost séparée qui publie seulement un article, identifié par son _id .
Meteor.publish('posts', function(options) {
return Posts.find({}, options);
});
Meteor.publish('singlePost', function(id) {
check(id, String)
return Posts.find(id);
});
//...
?
derniers articles
vous pouvez avoir plus d une publication pour chaque collection
Donc pour retrouver nos articles manquants
publication
cifique
.
n
/
.
server publications js
Maintenant
,
-
ôé
abonnons nous aux bons articles c
la publication
comments
'
sur la fonction
simplement ajouter l abonnement à
notre abonnement à la route
t
waitOn
singlePost
'
.
client
é
Nous nous sommes d
de la route
.
ici
'
é
jà abonn
postPage , donc nous pouvons
'
Et n oublions pas d ajouter
é
galement
postEdit , vu qu elle nécessite aussi les mêmes données :
//...
Router.route('/posts/:_id', {
name: 'postPage',
waitOn: function() {
return [
Meteor.subscribe('singlePost', this.params._id),
Meteor.subscribe('comments', this.params._id)
];
},
data: function() { return Posts.findOne(this.params._id); }
});
Router.route('/posts/:_id/edit', {
name: 'postEdit',
waitOn: function() {
return Meteor.subscribe('singlePost', this.params._id);
},
data: function() { return Posts.findOne(this.params._id); }
});
//...
/
.
lib router js
Commit 12-6
…
Utiliser un abonnement à un unique article pour nous assu
Voir sur GitHub
Avec la pagination activ
é ,
e
s à
'
Lancer l instance
notre application ne souffre plus de probl
è
é
mes de mont
e en
,
charge
-
û
et les utilisateurs sont s
'
rs de contribuer avec m
è
serait il pas super de pouvoir d une mani
,
saviez pas
'
é é
c est pr
cis
'
'
ê
'
?
re ou d une autre classer ces liens
.
ment l objet du chapitre suivant
.
me plus de liens qu avant
Donc ne
Si vous ne le
Le Vote
13
,
Maintenant que notre site est en train de devenir populaire
rapidement devenir d
é
licat
.
trouver les meilleurs liens va
è
Ce que nous avons besoin est un syst
me de classement pour
.
ordonner nos articles
Nous pourrions construire un syst
,
perte de points dans le temps
,
Telescope
è
me de classement complexe avec karma
è
le grand fr
'
).
et plein d autres choses
re de Microscope
(
,
é
la plupart sont impl
,
Mais pour notre application
é
bas
sur une
é
ment
s dans
nous garderons les
'
.
choses simples et nous noterons juste les articles par le nombre de votes qu ils ont reçus
.
Commençons par donner aux utilisateurs un moyen de voter sur les articles
Modèle de données
Nous stockerons une liste de votants sur chaque article afin de savoir si on doit montrer le
ê
bouton de vote aux utilisateurs et pour emp
.
cher les personnes de voter deux fois
Confidentialité des données et Publications
,
Nous publierons ces listes de votants à tous les utilisateurs
automatiquement ces donn
ce qui rendra
é
es accessibles publiquement via la console du
.
navigateur
'
C est le type de probl
è
é
é
me sur la confidentialit
.
façon dont les collections fonctionnent
des donn
Par exemple
é
personnes soient capables de trouver qui a vot
,
es qui peut subvenir de la
-
voulons nous que les
pour leurs articles
'
rendre cette information disponible publiquement n aura pas r
é
cons
,
quences
Nous allons
é
facile la r
upvoters
é
é
,
Dans notre cas
ellement de
mais il est important de reconna tre au minimum le probl
è
.
me
é
galement d
é
cup
et
î
?
normaliser le nombre total de votants sur un article pour rendre plus
ration de ce chiffre
.
,
Donc nous ajouterons deux attributs à nos articles
votes . Commençons par les ajouter à notre fichier de pré
-
installation
:
// Données de préinstallation
if (Posts.find().count() === 0) {
var now = new Date().getTime();
// Créer deux utilisateurs
var tomId = Meteor.users.insert({
profile: { name: 'Tom Coleman' }
});
var tom = Meteor.users.findOne(tomId);
var sachaId = Meteor.users.insert({
profile: { name: 'Sacha Greif' }
});
var sacha = Meteor.users.findOne(sachaId);
var telescopeId = Posts.insert({
title: 'Introducing Telescope',
userId: sacha._id,
author: sacha.profile.name,
url: 'http://sachagreif.com/introducing-telescope/',
submitted: new Date(now - 7 * 3600 * 1000),
commentsCount: 2,
upvoters: [],
votes: 0
});
Comments.insert({
postId: telescopeId,
userId: tom._id,
author: tom.profile.name,
submitted: new Date(now - 5 * 3600 * 1000),
body: "C'est un projet intéressant Sacha, est-ce-que je peux y participe
r ?"
});
Comments.insert({
postId: telescopeId,
userId: sacha._id,
author: sacha.profile.name,
submitted: new Date(now - 3 * 3600 * 1000),
body: 'Bien sûr Tom !'
});
Posts.insert({
title: 'Meteor',
userId: tom._id,
author: tom.profile.name,
url: 'http://meteor.com',
submitted: new Date(now - 10 * 3600 * 1000),
commentsCount: 0,
upvoters: [],
votes: 0
});
Posts.insert({
title: 'The Meteor Book',
userId: tom._id,
author: tom.profile.name,
url: 'http://themeteorbook.com',
submitted: new Date(now - 12 * 3600 * 1000),
commentsCount: 0,
upvoters: [],
votes: 0
});
}
for (var i = 0; i < 10; i++) {
Posts.insert({
title: 'Test post #' + i,
author: sacha.profile.name,
userId: sacha._id,
url: 'http://google.com/?q=test-' + i,
submitted: new Date(now - i * 3600 * 1000 + 1),
commentsCount: 0,
upvoters: [],
votes: 0
});
}
/
.
server fixtures js
'
,
Comme d habitude
,
application
éé
propri
t
et cr
ê
arr
é
ez un nouvel utilisateur
é
s sont initialis
,
tez votre application
.
é
ex
meteor reset , redémarrez votre
cutez
-
Assurons nous
éé :
es quand les articles sont cr
s
é
galement ensuite que ces deux
//...
var postWithSameLink = Posts.findOne({url: postAttributes.url});
if (postWithSameLink) {
return {
postExists: true,
_id: postWithSameLink._id
}
}
var user = Meteor.user();
var post = _.extend(postAttributes, {
userId: user._id,
author: user.username,
submitted: new Date(),
commentsCount: 0,
upvoters: [],
votes: 0
});
var postId = Posts.insert(post);
return {
_id: postId
};
//...
/
.
collections posts js
Templates de vote
è
Premi
,
rement
nous allons ajouter un bouton de vote à notre article partiel et afficher le
nombre de votes dans les m
é
tadonn
é
'
es de l article
:
<template name="postItem">
<div class="post">
<a href="#" class="upvote btn btn-default"> </a>
<div class="post-content">
<h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
<p>
{{votes}} Votes,
submitted by {{author}},
<a href="{{pathFor 'postPage'}}">{{commentsCount}} comments</a>
{{#if ownPost}}<a href="{{pathFor 'postEdit'}}">Edit</a>{{/if}}
</p>
</div>
<a href="{{pathFor 'postPage'}}" class="discuss btn btn-default">Discuss
</a>
</div>
</template>
⬆
/
/
/ _
client templates posts post
.
item html
Le bouton de vote
,
Ensuite
bouton
:
é
nous allons appeler une m
'
thode serveur upvote quand l utilisateur clique sur le
//...
Template.postItem.events({
'click .upvote': function(e) {
e.preventDefault();
Meteor.call('upvote', this._id);
}
});
/
/
/ _
client templates posts post
,
Finalement
nous allons revenir à notre fichier
é
m
.
item js
ôé
thode Meteor c
t
lib/collections/posts.js
serveur qui votera pour les articles
et ajouter une
:
//...
Meteor.methods({
post: function(postAttributes) {
//...
},
upvote: function(postId) {
check(this.userId, String);
check(postId, String);
var post = Posts.findOne(postId);
if (!post)
throw new Meteor.Error('invalid', 'Post not found');
if (_.include(post.upvoters, this.userId))
throw new Meteor.Error('invalid', 'Already upvoted this post');
}
});
Posts.update(post._id, {
$addToSet: {upvoters: this.userId},
$inc: {votes: 1}
});
//...
/
/
.
lib collections posts js
Commit 13-1
Algorithme basique de vote
'
Voir sur GitHub
é
Cette m
.
thode est assez directe
'
'
é
'
doublement que l utilisateur n a pas d
incr
'é
L
é
Lancer l instance
é
Nous faisons quelques v
assurer que l utilisateur est authentifi
.
'
é
rifications de s
é
et que l article existe r
é
é
jà vot
,
pour cet article
'
.
ellement
'
'
é
curit
pour nous
Puis nous v
é
et si c est le cas nous
mentons le score total de vote et ajoutons l utilisateur à l ensemble des votants
é
tape finale est int
,
ressante
é
comme nous avons utilis
,
en a beaucoup plus à apprendre
ajoute un item à une propri
éé
t
'
'
é
deux op
ê
mais ces deux sont extr
.
é
rateurs Mongo sp
mement pratique
é ,
de tableau tant qu elle n existe pas d
.
rifions
jà
et
.
ciaux
Il y
: $addToSet
$inc
incr
é
mente
simplement un entier
Optimisations de l'interface utilisateur
'
'
é,
Si l utilisateur n est pas authentifi
é
Pour refl
,
ter ça dans notre UI
une classe CSS
disabled
é
ou a d
é
jà vot
,
un article
é
il ne sera pas autoris
nous utiliserons un helper pour ajouter de façon conditionnelle
au bouton de vote
.
<template name="postItem">
<div class="post">
<a href="#" class="upvote btn {{upvotedClass}}"> </a>
<div class="post-content">
//...
</div>
</template>
⬆
/
/
/ _
client templates posts post
.
à voter
.
item html
Template.postItem.helpers({
ownPost: function() {
//...
},
domain: function() {
//...
},
upvotedClass: function() {
var userId = Meteor.userId();
if (userId && !_.include(this.upvoters, userId)) {
return 'btn-primary upvotable';
} else {
return 'disabled';
}
}
});
Template.postItem.events({
'click .upvotable': function(e) {
e.preventDefault();
Meteor.call('upvote', this._id);
}
});
/
/
/ _
client templates posts post
.
item js
Nous changeons notre classe
'é é
l
v
nement click
é
galement
.
.upvote
en
'
.upvotable , donc n oubliez pas de changer
Griser les boutons vote.
Commit 13-2
é
Griser lien vote quand non authentifi
,
é
d
Lancer l instance
vous pouvez noter que les articles avec un seul vote sont
.
prenons le temps de pluraliser ces labels proprement
é,
compliqu
'
é.
jà vot
'
Voir sur GitHub
Ensuite
/
'
é
Pluralisation peut
s
ê
é é
n
.
'
ù:
ral que nous pourrons utiliser n importe o
Template.registerHelper('pluralize', function(n, thing) {
// pluraliser assez simpliste
if (n === 1) {
return '1 ' + thing;
} else {
return n + ' ' + thing + 's';
}
});
”,
votes
donc
tre un processus
mais pour l instant nous ferons ça d une façon assez simpliste
un helper Spacebars g
“
é 1
tiquet
é
Nous allons cr
er
/
/
.
client helpers spacebars js
Les helpers que nous avons cr
'
.
s appliquent
qui peut
éé
Mais en utilisant
ê
é
tre utilis
'
à l int
s avant ont
éé
t
é
reli
au manager et template auxquels ils
Template.registerHelper , nous avons créé un helper
'
é
rieur d un template
global
:
<template name="postItem">
//...
<p>
{{pluralize votes "Vote"}},
submitted by {{author}},
<a href="{{pathFor 'postPage'}}">{{pluralize commentsCount "comment"}}</a>
{{#if ownPost}}<a href="{{pathFor 'postEdit'}}">Edit</a>{{/if}}
</p>
//...
</template>
/
/
/ _
client templates posts post
.
item html
Perfectionner Pluralisation Propre (maintenant dites ça 10 fois)
Commit 13-3
é
Helper pluraliser ajout
pour un meilleur format texte
'
Voir sur GitHub
“1
Maintenant vous devriez voir
.
Lancer l instance
”.
vote
Algorithme de vote plus intelligent
Notre code de vote est bon
,
é
nous cr
ons deux appels vers Mongo
è
Il y a deux probl
é
donn
'
.
mes avec ça
.
es deux fois
1. é
R
é
cup
3.
'
un pour trouver l article
è
,
rement
,
'
,
'
Dans la m
.
'
'
c est un peu inefficace d aller vers la base de
.
Nous suivons
:
'
é .
es
é.
rifier si l utilisateur a vot
,
Sinon
'
faire un vote par l utilisateur
--
.
'
ê
me utilisateur vote plusieurs fois pour l article entre les
Notre code actuel ouvre la porte au utilisateur capables de voter pour le m
.
,
thode upvote
Que se passe t il si le m
fois
é
l autre pour le mettre à jour
il introduit une concurrence
rer l article de la base de donn
2. é
V
Premi
:
Mais plus important
l algorithme suivant
.
mais nous pouvons encore faire mieux
Heureusement
,
'ê
Mongo nous permet d
une seule commande Mongo
:
é
tapes
ê
1
et
3
?
me article deux
tre plus intelligent et combine les
é
tapes
-
13
dans
//...
Meteor.methods({
post: function(postAttributes) {
//...
},
upvote: function(postId) {
check(this.userId, String);
check(postId, String);
var affected = Posts.update({
_id: postId,
upvoters: {$ne: this.userId}
}, {
$addToSet: {upvoters: this.userId},
$inc: {votes: 1}
});
if (! affected)
throw new Meteor.Error('invalid', "Vous n'avez pas pu voter pour ce post
.");
}
});
//...
/
.
collections posts js
Commit 13-4
Meilleur algorithme de vote
'
Voir sur GitHub
'
cet utilisateur n a pas d
é,
vot
é
jà vot
é,
'
Lancer l instance
' “
Ce que nous sommes en train de dire c est
trouve tous les articles avec cet
ê
”. '
et mets les à jour dans ce sens
il trouvera bien entendu l article avec cet
la requ
.
te correspondra à aucun documents
,
'
id
pour lesquels
'
Si l utilisateur n a pas d
'
id . D un autre côté si l utilisateur
é
et par cons
é,
a vot
quent rien ne se passera
é
.
jà
alors
Compensation de la latence
é
Disons que vous avez essay
de tricher et envoy
é
un de vos articles en haut de la lise
:
en bidouillant son nombre de votes
> Posts.update(postId, {$set: {votes: 10000}});
Console du navigateur
(
ù postId
O
' '
)
est l id d un de vos articles
è
Cette tentative impudente de jouer avec le syst
deny()
é .
rejet
(
é
et imm
diatement
e
.
en action
ê
Ça peut
' -
é
Que s est il pass
sans incident
.
?
,
é
vous pourriez voir la compensation de latence
'
é
,
,
ment
sur le serveur
é
sultat final
:
é
une erreur
,
en local
'
a
éé
t
éé
é
t
appliqu
é.
rejet
ponde
.
pas aider mais fait confiance à la collection en local
'
,
e
.
Puis un peu plus tard
),
le
è .
en disant à la collection en local de revenir en arri
é
,
a
cutez Meteor sur votre propre machine
en attendant que le serveur r
refuse la modification
update
le
te de la liste
donc l article a atteint le haut de la liste
update
le
ê
vement en t
,
Posts
Dans votre collection
en millisecondes si vous ex
serveur a retourn
è
mais l article bondira bri
Ça arrive instantan
Pendant ce temps
mesur
,
.
tre rapide
avant de revenir à sa position
é
e par notre callback
?)
,
Le r
r
collections/posts.js , vous vous souvenez
dans
Mais si vous regardez attentivement
(
éé
me serait g
'
re
l interface utilisateur ne peut
ô
Aussit
t que le serveur revient et
les interfaces utilisateur s adaptent pour refl
é
.
ter ça
Classer les articles de la première page
é
Maintenant que nous avons un score pour chaque article bas
.
affichons la liste des meilleurs articles
é
souscriptions s
é é .
plus g
n
ral
par
é
,
Pour faire ça
es sur la collection article
,
,
sur le nombre de votes
é
nous allons voir comment g
et rendre notre template
rer deux
postList
un peu
Pour commencer
'
,
,
.
nous voulons avoir deux souscriptions
une pour chaque ordre de tri
ê
L astuce ici est que les deux souscriptions souscriront à la m
é
seulement avec des arguments diff
Nous allons
é
galement cr
rents
pagination bien sur
,
Pour faire cela
nous
é
tendrons notre
NewPostListController
ê
exactement les m
donnant un seul
é
er deux nouvelles routes appel
).
et
/new
et
/best
(
es
avec
PostsListController
BestPostsListController
newPosts
/new/5
NewPostsListController
é
de Iron Router
éé
Remplaçons donc la propri
t
de tri
.
'ù
d o
é
h
riter
{submitted: -1}
.
.
distincts
this.sort , qui sera fournie par NewPostsListController
bestPosts ,
/best/5
,
pour notre
ô
leurs
é
Ça nous laissera r
home
De plus
dans
et
et
dans deux contr
mes options de routes pour les deux routes
illustration de la flexibilit
posts ,
.
é
accessibles respectivement aux URLs
me publication
'
et
newPosts , en nous
c est juste une belle
PostsListController
et
utiliser
par
BestPostsListController :
//...
PostsListController = RouteController.extend({
template: 'postsList',
increment: 5,
postsLimit: function() {
return parseInt(this.params.postsLimit) || this.increment;
},
findOptions: function() {
return {sort: this.sort, limit: this.postsLimit()};
},
subscriptions: function() {
this.postsSub = Meteor.subscribe('posts', this.findOptions());
},
posts: function() {
return Posts.find({}, this.findOptions());
},
data: function() {
var hasMore = this.posts().count() === this.postsLimit();
return {
posts: this.posts(),
ready: this.postsSub.ready,
nextPath: hasMore ? this.nextPath() : null
};
}
});
NewPostsController = PostsListController.extend({
sort: {submitted: -1, _id: -1},
nextPath: function() {
return Router.routes.newPosts.path({postsLimit: this.postsLimit() + this
.increment})
}
});
BestPostsController = PostsListController.extend({
sort: {votes: -1, submitted: -1, _id: -1},
nextPath: function() {
return Router.routes.bestPosts.path({postsLimit: this.postsLimit() + thi
s.increment})
}
});
Router.route('/', {
name: 'home',
controller: NewPostsController
});
Router.route('/new/:postsLimit?', {name: 'newPosts'});
Router.route('/best/:postsLimit?', {name: 'bestPosts'});
/
.
lib router js
'
Notez que maintenant que nous avons plus d une route
hors de
PostListController
,
nous prenons la logique
NewPostsController
et la plaçons dans
nextPath
et
BestPostsController , à partir du moment où le chemin sera différent dans les deux cas.
,
De plus
puis par
quand nous trions par
_id
'
è
pour nous assurer que l ordre est enti
ô
Avec nos nouveaux contr
é
d
barrasser de la route
leurs en place
postList
,
éé
pr
c
.
dente
è
me nous
Supprimez simplement le code suivant
' -ê
galement des liens dans l en t
:
.
é
é.
cifi
nous pouvons maintenant sans probl
lib router js
Nous ajouterons
é
rement sp
Router.route('/:postsLimit?', {
name: 'postsList'
})
/
'
votes , nous avons des tris ultérieurs par horodatage d envoi
te
:
<template name="header">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="col
lapse" data-target="#navigation">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{pathFor 'home'}}">Microscope</a>
</div>
<div class="collapse navbar-collapse" id="navigation">
<ul class="nav navbar-nav">
<li>
<a href="{{pathFor 'newPosts'}}">New</a>
</li>
<li>
<a href="{{pathFor 'bestPosts'}}">Best</a>
</li>
{{#if currentUser}}
<li>
<a href="{{pathFor 'postSubmit'}}">Submit Post</a>
</li>
<li class="dropdown">
{{> notifications}}
</li>
{{/if}}
</ul>
<ul class="nav navbar-nav navbar-right">
{{> loginButtons}}
</ul>
</div>
</nav>
</template>
/
/
/
.
client templates includes header html
Et finalement
,
nous avons
'
suppression d article
:
é
galement besoin de mettre à jour notre gestionnaire de
'click .delete': function(e) {
e.preventDefault();
}
/
if (confirm("Delete this post?")) {
var currentPostId = this._id;
Posts.remove(currentPostId);
Router.go('home');
}
/
/
_
client templates posts posts
Avec tout cela de fait
,
.
edit js
.
nous avons maintenant une liste des meilleurs posts
Classer par points
Routes ajout
é
Commit 13-5
'
,
es pour les listes d articles
Voir sur GitHub
'
…
et pages pour
Lancer l instance
Une meilleur en-tête
'
,
Maintenant que nous avons deux pages de liste d articles
laquelle vous
é
.
vident
ê
tes en train de regarder
Nous allons cr
.
ê
é
er un gestionnaire
é
header.js
et cr
é
tre difficile de savoir
-ê
Donc revisitons notre en t
courant et une ou plusieurs routes nomm
navigation
il peut
te pour rendre ça plus
er un helper qui utilise le chemin
es pour ajouter une class active dans nos items de
:
é
La raison pour laquelle nous voulons supporter de multiples routes nomm
routes
ê
le m
home
et
newPosts
me template
.
(
qui correspondent respectivement aux URLs
Ça signifie que notre
pour rendre actif le tag
<li>
activeRouteClass
.
dans les deux cas
devrait
ê
/
es est que les deux
et
/new
)
invoque
tre assez intelligente
<template name="header">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="col
lapse" data-target="#navigation">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{pathFor 'home'}}">Microscope</a>
</div>
<div class="collapse navbar-collapse" id="navigation">
<ul class="nav navbar-nav">
<li class="{{activeRouteClass 'home' 'newPosts'}}">
<a href="{{pathFor 'newPosts'}}">New</a>
</li>
<li class="{{activeRouteClass 'bestPosts'}}">
<a href="{{pathFor 'bestPosts'}}">Best</a>
</li>
{{#if currentUser}}
<li class="{{activeRouteClass 'postSubmit'}}">
<a href="{{pathFor 'postSubmit'}}">Submit Post</a>
</li>
<li class="dropdown">
{{> notifications}}
</li>
{{/if}}
</ul>
<ul class="nav navbar-nav navbar-right">
{{> loginButtons}}
</ul>
</div>
</nav>
</template>
/
/
/
.
client templates includes header html
Template.header.helpers({
activeRouteClass: function(/* route names */) {
var args = Array.prototype.slice.call(arguments, 0);
args.pop();
var active = _.any(args, function(name) {
return Router.current() && Router.current().route.getName() === name
});
}
});
/
return active && 'active';
/
/
.
client templates includes header js
Montrer la page active
Arguments des helpers
'
é
,
Nous n avons pas utilis
'
d autres tags Spacebars
é
ce patron sp
'
,
cifique jusqu à maintenant
mais tout comme
.
les tags de template helper peuvent prendre des arguments
é
Et pendant que vous pouvez bien entendu passer des arguments nomm
dans votre fonction
,
è
param
é
é é
vous pouvez
tres anonymes et les r
cup
é
galement passer un nombre non sp
'
.
é
cifi
arguments
rer en appelant l objet
é
s sp
cifiques
de
dans la
fonction
,
Dans ce dernier cas
tableau Javascript classique et ensuite appeler
é
du hash ajout
,
(. .
i e
,
le helper
Any()
activeRouteClass
de Underscore pour voir si certaines des routes
leur url correspondante est
é
).
gale au chemin courant
, any()
,
myString
nous prenons avantage du patron Javascript
retourne
false , mais true && myString
é
Classes active ajout
Voir sur GitHub
' -ê
es à l en t
te
.
'
Lancer l instance
é ,
el
vous verrez les
.
items monter et descendre la page d accueil en fonction de leur classement
'
ù false &&
o
myString .
Maintenant que les utilisateurs peuvent voter sur les articles en temps r
'
true .
retournera
boolean && string
retourne
Commit 13-6
'
barrasser
prendre une liste de noms de
Si une de ces routes correspond avec le chemin courant
Finalement
é
dessus pour vous d
en
.
et ensuite utilise le helper
passent le test
pop()
arguments
à la fin par Spacebars
Pour chaque item de navigation
routes
'
vous voudrez probablement convertir l objet
?
Mais ne serait il
é
pas joli s il y avait un moyen d affiner tout ça avec quelques animations bien temporis
es
Publications Avancées
,
À partir de maintenant
13.5
SIDEBAR
abonnements interagissent
.
’
e de comment les publications et les
î
é
Donc passez le cap de l entra nement et examinez des sc
é.
un peu plus avanc
é
vous devriez avoir une bonne id
narios
s
Publier une collection de multiples fois
è
Dans notre premi
,
re annexe à propos des publications
'
,
classiques de publications et d abonnements
_publishCursor
è
Premi
,
rement
et nous avons appris comment la fonction
é
nous a rendu la tâche facile pour les impl
rappelons ce que
_publishCursor
.
me nom
:
é,
ê
.
menter dans nos propres sites
fait pour nous exactement
les documents qui correspondent à un curseur donn
client du m
nous avons vu quelques patterns
il prend tous
ôé
et les envoie dans la collection c
'
Notez que le nom de la publication n est en aucun cas impliqu
t
é.
'
'
Cela signifie que nous avons plus d une publication reliant les versions client et serveur d une
.
collection
é
Nous avons d
é
avons publi
jà rencontr
-
é
un sous ensemble pagin
é
'
é
'
quand nous
é.
de tous les articles en plus de l article affich
'
'
Un autre cas similaire est de publier une vue d ensemble d un large
aussi bien que les d
,
ce pattern dans notre chapitre sur la pagination
tails complets d un seul item
:
é
,
chantillons de documents
Publier une collection deux fois
Meteor.publish('allPosts', function() {
return Posts.find({}, {fields: {title: true, author: true}});
});
Meteor.publish('postDetail', function(postId) {
return Posts.find(postId);
});
'
,
Maintenant que le client s abonne à ces deux publications
de deux sources
'
:
'
sa collection
'posts'
,
une liste de titres et de noms d auteur du premier abonnement
è
complets d un article provenant du deuxi
.
me abonnement
est remplie
é
et les d
tails
(
'
é
Vous pouvez r
'
aliser que l article publi
-
é
postDetail
par
est
é
)
éé .
bien qu avec seulement un sous ensemble de ses propri
'
t
s
é
galement publi
,
Cependant
' '
par
allPosts
Meteor prend soin
'
du chevauchement en rassemblant les champs et en s assurant qu il n y a pas d article
é.
dupliqu
'
é
C est g
,
nial
parce que maintenant quand nous affichons la liste r
nous avons affaire à des objets de donn
nous avons besoin
.
Cependant
,
é
,
capitulative des articles
é
es qui ont juste assez de donn
es pour afficher ce que
quand nous affichons la page pour un seul article
tout ce que nous avons besoin pour le montrer
'
é
.
û,
Bien s
r
,
nous avons
nous devons faire attention sur le
client à ne pas s attendre à ce que tous les champs soient disponibles sur tous les articles dans
ce cas
–'
c est un pi
è
ge habituel
Il convient de noter que vous n
è
pouvez tr
é
diff
s bien publier les m
!
'ê
é
tes pas limit
ê
éé
mes propri
t
aux diff
é
éé
rentes propri
t
.
s des documents
,
s dans les deux publications
Vous
mais les trier
.
remment
Meteor.publish('newPosts', function(limit) {
return Posts.find({}, {sort: {submitted: -1}, limit: limit});
});
Meteor.publish('bestPosts', function(limit) {
return Posts.find({}, {sort: {votes: -1, submitted: -1}, limit: limit});
});
/
.
server publications js
S'abonner à une publication plusieurs fois
'
.
Nous venons juste de voir comment publier une collection plus d une fois
pouvez accomplir le m
'
ê
é
me r
sultat avec un autre pattern
: é
cr
'
Il s av
è
re que vous
,
er une seule publication
mais
.
s y abonner plusieurs fois
,
Dans Microscope
é
configure et d
nous nous abonnons à la publication
truit chaque abonnement pour nous
é
puisse pas nous abonner plusieurs fois simultan
.
posts
plusieurs fois
'
,
mais Iron Router
'
Pourtant il n y a aucune raison qu on ne
.
ment
,
Par exemple
é
r
disons que nous voulons charger en m
é
cents en m
moire
ê
me temps les meilleurs articles et les plus
:
S'abonner deux fois à une publication
Nous mettons en place une publication
:
Meteor.publish('posts', function(options) {
return Posts.find({}, options);
});
Et ensuite nous nous abonnons à cette publication plusieurs fois
exactement ce que nous faisons dans Microscope
:
.
'
En fait c est plus ou moins
Meteor.subscribe('posts', {submitted: -1, limit: 10});
Meteor.subscribe('posts', {baseScore: -1, submitted: -1, limit: 10});
' -
'
Qu est ce qu il se passe exactement
?
é
Chaque navigateur ouvre deux abonnements diff
ê
chacun se connecte à la m
me publication sur le serveur
é
Chaque abonnement fournit des arguments diff
,
fondamentalement
é
posts
collection
chaque fois un ensemble
et envoy
ê
é
le sera
,
rents à la publication
é
diff
)
rent
ù
!
mais
de documents est recueilli de la
ôé
t
.
client
ê
me abonnement avec les m
Difficile d imaginer beaucoup de situations o
flexibilit
.
dans le tuyau vers la collection c
Vous pouvez aussi souscrire deux fois au m
'
(
'
,
rents
,
c est utile
mais peut
ê
!
mes arguments '
tre qu un jour cette
De multiples collections dans un seul abonnement
Contrairement aux bases de donn
é
é
bases de donn
ô
es NoSQL comme Mongo sont plut
.
é
Nous avons ajout
’
é
t dans la d
Voyons comment ça fonctionne dans le contexte de Meteor
Regardons un exemple concret
,
es traditionnelles comme MySQL qui utilise des joins
les
é.
normalisation et l embarqu
.
,
des commentaires à nos articles
'
'
,
et depuis
nous sommes heureux de publier uniquement les commentaires de l article que l utilisateur
.
est en train de lire
,
Cependant
è
premi
supposez que nous voulions montrer les commentaires de tous les articles de la
re page
'
(
garder en t
classique d utilisation pr
,
articles
'
).
ê
te que ces articles changeront quand nous les paginerons
é
sente une bonne raison pour embarquer les commentaires dans les
é
et en fait c est ce qui nous pousse à d
.
normaliser les compteurs de commentaires
û
Bien s
,
r nous pouvons toujours juste embarquer les commentaires dans les articles
é
d
é
normalisation
é
avec des collections diff
se
Comments . Mais comme nous avons vu précédemment dans le
barrasser de la collection
chapitre de d
Ce cas
,
é é
en faisant ça nous perdrions certains des b
.
rentes
n
fices de travailler
'
è
Mais il s av
'
'
re qu il y a une astuce impliquant les abonnements qui rende possible d inclure
nos commentaires tout en pr
'
é
é
servant des collections s
Supposons qu avec notre premi
'
è
par
,
re page de liste d articles
é .
es
nous voulons nous abonner à une
.
liste des deux top commentaires de chaque article
'
é
Il serait difficile d accomplir ça avec une publication de commentaires ind
é
sp
'
cialement si la liste d articles
Nous devrions
é
é
é
tait limit
'
d une certaine façon
crire une publication qui ressemblerait à ça
Deux collections dans un abonnement
:
(
disons
,
,
pendants
les
10
plus r
é
).
cents
Meteor.publish('topComments', function(topPostIds) {
return Comments.find({postId: topPostIds});
});
è
Ça causerait un probl
é
d
é
mont
-
me de performance
éé
e et r
.
,
:
topPostsIds
.
tre
change
Nous utilisons juste le fait que nous ne pouvons pas seulement
avoir plus d une publication par collection
par publication
'ê
comme la publication aurait besoin d
tablie à chaque fois que la liste de
Il y a un moyen de faire ça
'
,
'
mais nous pouvons aussi avoir plus d une collection
Meteor.publish('topPosts', function(limit) {
var sub = this, commentHandles = [], postHandle = null;
// Envoyer les deux top commentaires d'un post unique
function publishPostComments(postId) {
var commentsCursor = Comments.find({postId: postId}, {limit: 2});
commentHandles[postId] =
Mongo.Collection._publishCursor(commentsCursor, sub, 'comments');
}
postHandle = Posts.find({}, {limit: limit}).observeChanges({
added: function(id, post) {
publishPostComments(postId);
sub.added('posts', id, post);
},
changed: function(id, fields) {
sub.changed('posts', id, fields);
},
removed: function(id) {
// Stopper l'observation des changelents sur les commentaires de l'art
icle
commentHandles[id] && commentHandles[id].stop();
// Supprimer l'article
sub.removed('posts', id);
}
});
sub.ready();
// S'assurer que nous nettoyons tout (notez que `_publishCursor`
// fait ça pour nous avec les observateurs de commentaire)
sub.onStop(function() { postHandle.stop(); });
});
,
Notez que nous ne retournons rien dans cette publication
ê
m
mes manuellement des messages à
pas besoin de demander à
Maintenant
,
sub
_publishCursor
(
via
.added()
et consorts
é.
automatiquement les deux top commentaires qui y sont attach
'
).
'
Donc nous n avons
.
de faire ça pour nous en retournant un curseur
chaque fois que nous publions un article nous publions
appel d abonnement
-
comme nous envoyons nous
!
è
Bien que Meteor ne rend pas encore cette approche tr
,
s direct
s
é
galement
Et tout ça avec un seul
vous pouvez voir chercher le
paquet
publish-with-relations
plus facile à utiliser
,
sur Atmosphere
qui a pour objectif de rendre ce pattern
.
Relier des collections différentes
' -
é
Qu est ce que notre nouvelle connaissance sur la flexibilit
apporter
?
,
Bien
'
si nous n utilisons pas
des abonnements pourrait nous
'
_publishCursor , nous n avons pas besoin de suivre la
'
ê
contrainte que la collection source sur le serveur a besoin d avoir le m
.
me nom que la
collection cible sur le client
Une collection pour deux abonnements
Une raison de pourquoi nous voudrions faire ça est Single Table Inheritance
(é
h
ritage de
).
tableau unique
Supposons que nous voulions r
ces champs communs stock
éé
f
é
éé é è
s mais aussi a diff
nous pourrions construire un syst
,
classique ID
timestamp et title
juste du texte
;
'
,
rencer divers types d objets de nos articles
r
l
g
.
rement dans le contenu
è
ù
me de blog comme Tumblr o
é
mais en plus peut
,
Par exemple
chaque article poss
é
galement g
rer une image
,
è
é ,
vid
o
de le
,
lien
ou
.
'resources' , en utilisant un
Nous pouvons stocker tous ces objets dans une seule collection
attribut
dont chacun de
type
'
(
. video , image , link ,
pour indiquer quelle sorte d objet ils sont
Et bien que nous avons une seule collection
Resources
sur le serveur
transformer cette unique collection en multiples collections
client avec ce petit tour de magie
,
)
..
etc
nous pouvons
Videos , Images , etc. sur le
:
Meteor.publish('videos', function() {
var sub = this;
var videosCursor = Resources.find({type: 'video'});
Mongo.Collection._publishCursor(videosCursor, sub, 'videos');
// _publishCursor ne fait pas l'appel pour nous au cas où nous voudrions
le faire plusieurs fois.
sub.ready();
});
Nous disons à
,
ferait
_publishCursor
é
de publier nos vid
ô
mais plut
t que de publier à la collection
'resources'
publions de
é
Une autre id
vers
'
os
(
resources
,
sur le client
ôé
t
serveur !
ôé
,
Par exemple
ôé
tiers et les publier dans une collection c
Grâce à la flexibilit
é
'
,
de l API publish
que le curseur
à la place nous
'videos' .
e similaire est d utiliser publish avec une collection c
tout de collection c
)
juste en retournant
t
vous pouvez r
é
é
cup
.
é
s sont infinies
ù
client o
é
rer les donn
client
les possibilit
t
.
'
'
il n y a pas du
es d un service
Animations
////
Meteor & the DOM
////
////
////
////
////
2. ////
3. ////
4. ////
5. ////
6. ////
////
1.
14
Swtiching two posts
////
////
////
Proper Timing
////
////
////
////
////
////
CSS Positioning
////
////
////
////
////
.post{
position:relative;
transition:all 300ms 0ms ease-in;
}
/
/
.
client stylesheets style css
////
////
Position:absolute
////
////
Total Recall
////
////
////
////
////
Ranking Posts
////
////
////
////
Template.postsList.helpers({
postsWithRank: function() {
this.posts.rewind();
return this.posts.map(function(post, index, cursor) {
post._rank = index;
return post;
});
}
});
/
/
/
/
_
client views posts posts
.
list js
////
////
<template name="postsList">
<div class="posts">
{{#each postsWithRank}}
{{> postItem}}
{{/each}}
{{#if nextPath}}
<a class="load-more" href="{{nextPath}}">Load more</a>
{{/if}}
</div>
</template>
/
/
/
/
_
client views posts posts
.
list html
Be Kind, Rewind
////
////
////
Putting it together
////
Template.postItem.helpers({
//...
});
Template.postItem.rendered = function(){
// animate post from previous position to new position
var instance = this;
var rank = instance.data._rank;
var $this = $(this.firstNode);
var postHeight = 80;
var newPosition = rank * postHeight;
// if element has a currentPosition (i.e. it's not the first ever render)
if (typeof(instance.currentPosition) !== 'undefined') {
var previousPosition = instance.currentPosition;
// calculate difference between old position and new position and send e
lement there
var delta = previousPosition - newPosition;
$this.css("top", delta + "px");
}
// let it draw in the old position, then..
Meteor.defer(function() {
instance.currentPosition = newPosition;
// bring element back to its new original position
$this.css("top", "0px");
});
};
Template.postItem.events({
//...
});
/
/
/
/ _
client views posts post
.
item js
Commit 14-1
.
Added post reordering animation
Voir sur GitHub
////
'
Lancer l instance
////
////
Animating New Posts
////
////
////
2. ////
////
1.
////
Template.postItem.helpers({
//...
});
Template.postItem.rendered = function(){
// animate post from previous position to new position
var instance = this;
var rank = instance.data._rank;
var $this = $(this.firstNode);
var postHeight = 80;
var newPosition = rank * postHeight;
// if element has a currentPosition (i.e. it's not the first ever render)
if (typeof(instance.currentPosition) !== 'undefined') {
var previousPosition = instance.currentPosition;
// calculate difference between old position and new position and send e
lement there
var delta = previousPosition - newPosition;
$this.css("top", delta + "px");
} else {
// it's the first ever render, so hide element
$this.addClass("invisible");
}
// let it draw in the old position, then..
Meteor.defer(function() {
instance.currentPosition = newPosition;
// bring element back to its new original position
$this.css("top", "0px").removeClass("invisible");
});
};
Template.postItem.events({
//...
});
/
/
/
/ _
client views posts post
.
item js
Commit 14-2
.
Fade items in when they are drawn
Voir sur GitHub
'
Lancer l instance
////
CSS & JavaScript
////
////
////
Vocabulaire
99
Client
Lorsque nous parlons de client
,
nous faisons r
éé
f
rence au code qui tourne dans le navigateur
,
web des utilisateurs
'
,
que ce soit un navigateur traditionnel comme Firefox ou Safari
ou bien
.
quelque chose d aussi complexe que UIWebView dans une application native pour iPhone
Collection
'
ô
Une collection Meteor est l entrep
é
synchronis
entre le client et le serveur
é é
g
n
é
t de donn
.
é
datastore
)
qui est automatiquement
Les collections ont un nom
. ê
ralement sur le client et sur le serveur
ont une API commune bas
(
es
'
M
(
)
. posts ,
ex
é
me si elles se comportent diff
et existent
,
remment
elles
.
e sur l API de Mongo
Computation
“
Une
computation
”
les sources de donn
versatiles
é
lui d
(
'
est un bloc de code qui tourne à chaque fois qu il y a un changement dans
é
é
es versatiles dont il d
)
par exemple une variable de session
finir une computation
.
pend
.
é
Si vous avez une source de donn
es
et que vous voulez interagir avec elle
,
il faudra
Curseur (Cursor)
'
ê
Un curseur est le produit d une requ
'
'
curseur n est pas qu un tableau de r
.
te sur une collection Mongo
é
,
sultats
,
Au niveau du client
é
mais un objet r
actif qui peut
é,
lorsque des objets dans la collection en question sont ajout
s
enlev
ê
tre observ
é
un
é
é.
s et modifi
s
DDP
,
DDP
protocole de distribution de donn
é
synchroniser les collections et faire les appels de m
é é
protocole g
é .
donn
es
n
,
es de Meteor
é
é
est le protocole utilis
thodes
.
pour
éê
DDP est suppos
tre un
é
rique qui prend la place du HTTP pour les applications en temps r
el lourdes en
Tracker
Tracker est le syst
è
me r
é
.
actif de Meteor
é
automatiquement synchronis
Tracker agit dans les coulisses pour garder le HTML
è
avec le mod
é
le de donn
.
es choisi
Document
Mongo utilise les
“
”
documents
collections sont appel
é
s
“
é
”.
documents
)
peuvent pas contenir de fonctions
suivre les donn
es sur DDP
é
pour stocker les donn
.
es et donc les objets appartenant aux
(
Ce sont des objets JavaScript de base
éé
avec une propri
t
é
sp
ciale
_id
ê
m
'
me s ils ne
qui permet à Meteor de
Helpers
é é
Quand un template a besoin de g
,
document
n
'
éé
rer quelque chose de plus complexe qu une propri
il peut faire appel à un helper
,
t
de
.
une fonction qui aide pour le rendu
Compensation de latence (Latency compensation)
'
C est une technique qui permet de simuler des appels de m
é
les d
é
lais en attentant la r
é
é
thodes du cot
client pour
é
viter
.
ponse du serveur
Le groupe de développement de Meteor (Meteor Development Group, MDG)
'
é
L entreprise d
veloppant actuellement Meteor
,
-
par opposition avec le framework lui m
ê
.
me
Méthode (Method)
é
Une m
é
thode Meteor est un appel de proc
é
une logique sp
Les m
é
thodes ont
é
ciale pour d
tecter les changements dans les collections ainsi que des
é
m
.
dure du client vers le serveur
é .
canismes de compensation de d
lai
MiniMongo
La collection cot
é
é
client est stock
e dans un datastore qui offre une API comparable à Mongo
La librairie qui supporte cette API est appel
é
e
“
”
MiniMongo
'
pour indiquer que c est une
.
é
version simplifi
è
e de Mongo qui op
è
re enti
é
rement dans la m
.
moire
Paquet (Package)
Un paquet Meteor peut
JavaScript destin
(
é
ê
é
tre du code JavaScript destin
),
comme par exemple SASS vers CSS
Un paquet est comme une biblioth
è
liste compl
,
à tourner sur le client
du code
.
ou des ressources à traiter
.
que surpuissante
Non seulement Meteor est livr
é
avec une
mais il y a aussi Atmosphere qui est une collection de
te de paquets de base
paquets offerts par la communaut
,
des instructions sur la gestion des ressources
è
,
à tourner sur le serveur
é.
Publication
Une publication est un jeu de donn
'
.
utilisateur qui s y abonne
Vous cr
é
é
es qui a un nom et qui est personnalis
é
pour chaque
.
ez une publication sur le serveur
Serveur (Server)
. .
Le serveur Meteor est un serveur HTTP et DDP via Node js
è
biblioth
Il est constitu
ques Meteor ainsi que du code JavaScript que vous avez cr
Quand le serveur Meteor d
automatiquement
).
é
,
marre
éé
é
il se connecte à la base de donn
é
de toutes les
é
.
du cot
du serveur
(
e Mongo
é
qui d
marre
Session
é
La session dans Meteor correspond à une source de donn
ê
'é
é
tre utilis
e par votre application pour garder l
é
es versatile du cot
'
,
client
qui peut
.
tat dans lequel se trouve l utilisateur
Abonnement (Subscription)
.
Un abonnement est une connexion à une publication pour un client particulier
’
est du code qui s ex
é
é
cute dans le navigateur et qui garde les donn
.
publication du serveur
Patron (Template)
'
L abonnement
é
es synchronis
es avec la
'
é é
Un patron permet de g
syst
n
.
rer de l HTML en Javascript
è
(
me de template sans logique
- ),
logic less
é
Par d
qui pourrait
ê
,
faut
tre
é
,
Meteor utilise Spacebars
tendu dans le futur
un
.
Contexte des données du patron (Template Data Context)
'
é è
Lorsqu un patron g
é
sp
n
,
re un rendu
,
JavaScript objects
peuvent
ê
éè
f
G
),
POJOs
tre beaucoup plus
n
é
re à un objet JavaScript qui livre des donn
. é é
cifiques à ses besoins
-
il se r
ralement ce sont de bons vieux objets JavaScript
(
é
labor
é
s et poss
der leur propres fonctions
.
- ê
'
plain old
,
souvent des documents appartenant à une collection
é
es
m
me s ils

Documents pareils