Tutoriel du tutoriel Ember.js. Application Super Rentals. Partie 1.2

Nous continuons à publier la traduction du tutoriel du guide officiel d'Ember.js. Le didacticiel se compose de deux parties et il s'agit de la deuxième moitié de la première partie du didacticiel. Nous vous rappelons que vous pouvez lire la première moitié de ce lien


La liste des sujets traités dans le didacticiel suggère:


  • Utilisation d'Ember CLI
  • Navigation dans les fichiers et les dossiers d'application Ember
  • Créer et lier entre les pages
  • Modèles et composants
  • Test automatisé
  • Travailler avec les données du serveur
  • Segments dynamiques dans les itinéraires
  • Services chez Ember
  • Bibliothèque de données Ember
  • Adaptateurs et sérialiseurs
  • Modèle de composant fournisseur

Asseyez-vous, ouvrez les terminaux, trouvez le projet sur votre ordinateur et passons à autre chose. Et rappelez-vous que si vous avez des difficultés, vous pouvez toujours demander de l'aide sur le canal communautaire Discord (sur le canal russe # lang-russian ), ainsi que sur le canal télégramme en langue russe ember_js


Détails des composants


Il est enfin temps de travailler sur la liste de location:



En compilant cette liste de propriétés locatives, vous découvrirez:


  • Génération de composants
  • Organisation du code à l'aide de composants d'espace de noms
  • Transférer des attributs HTML avec ...attributes
  • Déterminer la quantité appropriée de couverture de test

Génération de composants


Commençons par créer le composant <Rental> . Cette fois, nous allons utiliser le générateur de composants pour créer un modèle et un fichier de test pour nous:


 $ ember generate component rental installing component create app/components/rental.hbs skip app/components/rental.js tip to add a class, run `ember generate component-class rental` installing component-test create tests/integration/components/rental-test.js 

Le générateur a créé deux nouveaux fichiers pour nous: le modèle de composant dans app/components/rental.hbs et le fichier de test de composant dans tests/integration/components/rental-test.js .


Nous allons commencer par éditer le modèle. Codons en dur les détails d'un objet loué, puis remplaçons-le par des données réelles provenant du serveur.



Ensuite, nous écrirons un test pour nous assurer que tous les détails sont présents. Nous remplacerons le modèle de test généré pour nous par nos propres équipes, comme nous l'avons fait précédemment pour le composant <Jumbo> :



Les tests doivent réussir.



Enfin, ajoutons un nouveau composant au modèle d'index pour remplir la page.



Dans ce cas, nous devrions voir le composant <Rental> montrant notre Grand Old Mansion trois fois sur la page:



Tout semble plutôt bien pour un petit travail!


Organisation du code à l'aide d'espaces de noms


Ensuite, ajoutez une image pour la propriété locative. Nous utiliserons à nouveau le générateur de composants:


 $ ember generate component rental/image installing component create app/components/rental/image.hbs skip app/components/rental/image.js tip to add a class, run `ember generate component-class rental/image` installing component-test create tests/integration/components/rental/image-test.js 

Cette fois, nous avions / au nom du composant. Cela a conduit à la création d'un composant dans app/components/rental/image.hbs , qui peut être appelé <Rental::Image> .


Des composants similaires sont appelés composants d' espace de noms . L'espace de noms nous permet d'organiser nos composants en dossiers selon leur fonction. Ceci est complètement facultatif, mais pratique, surtout lorsque vous développez une grande application en équipe.


Transférer des attributs HTML avec ...attributes


Modifions le modèle de composant:



Au lieu de définir des valeurs spécifiques pour les attributs src et alt dans <img> , nous avons choisi le mot-clé ...attributes , qui est aussi parfois appelé «splattributes». Cela vous permet de passer des attributs HTML arbitraires lors de l'appel de ce composant, par exemple comme ceci:



Nous avons spécifié ici l'attribut HTML src et alt , qui seront transmis au composant et attachés à l'élément, où ...attributes sont appliqués dans le modèle de composant. Vous pouvez penser que cela est similaire à {{yield}} , mais uniquement pour les attributs HTML et non pour le contenu d'affichage. En fait, nous avons déjà utilisé cette fonction plus tôt lorsque nous avons transmis l'attribut class à <LinkTo> .



Ainsi, notre composant <Rental::Image> n'est associé à aucun bien locatif particulier sur le site. Bien sûr, tout est également codé en dur avec nous, mais nous nous en occuperons bientôt. En attendant, nous limiterons l'intégralité du code dur à un composant afin qu'il soit plus facile de l'effacer lorsque nous passons à l'extraction de données réelles.

En général, c'est une bonne idée d'ajouter ...attributes à l'élément racine de votre composant. Cela offrira une flexibilité maximale, car l'initiateur peut avoir besoin de passer des classes de style ou des attributs ARIA pour améliorer l'accessibilité.


Écrivons maintenant un test pour notre nouveau composant!



Déterminer la quantité appropriée de couverture de test


Enfin, nous devons également mettre à jour les tests du composant <Rental> pour nous assurer que nous avons bien appelé <Rental::Image> .



Puisque nous avons déjà écrit des tests liés à <Rental::Image> , nous pouvons ici omettre les détails et minimiser la vérification. Ainsi, nous n'avons pas non plus à mettre à jour le test <Rental> chaque fois que nous apportons des modifications à <Rental::Image> .



Composants interactifs


Dans ce chapitre, vous ajoutez de l'interactivité à la page, ce qui permet à l'utilisateur de cliquer sur l'image pour l'agrandir ou la réduire:



Dans ce cas, vous découvrirez:


  • Ajout d'un comportement aux composants avec des classes
  • Accéder aux états d'instance à partir de modèles
  • Gestion des états avec propriétés suivies
  • Utilisation de syntaxes conditionnelles dans les modèles
  • Répondre à l'interaction de l'utilisateur avec des actions
  • Comment appeler les modificateurs d'éléments
  • Test d'interaction avec l'utilisateur

Ajout d'un comportement aux composants avec des classes


Jusqu'à présent, tous les composants que nous avons écrits sont purement de présentation - ce ne sont que des fragments de balisage réutilisable. C'est, bien sûr, merveilleux, mais dans Ember, les composants peuvent faire beaucoup plus!


Parfois, vous souhaitez associer un comportement à vos composants afin qu'ils puissent faire des choses plus intéressantes. Par exemple, <LinkTo> peut répondre aux clics en modifiant l'URL et en passant à une autre page.


Ici, nous allons faire quelque chose de similaire! Nous allons implémenter les fonctionnalités de «View Larger» et «View Smaller» , qui permettront à nos utilisateurs de cliquer sur l'image à la maison, d'afficher la version plus grande et de cliquer à nouveau dessus pour revenir à la version plus petite.


En d'autres termes, nous avons besoin d'un moyen de basculer l' image entre l'un des deux états . Pour ce faire, nous avons besoin d'un moyen pour le composant de stocker deux états possibles et de savoir dans quel état il se trouve actuellement.


Ember nous permet en outre d'associer du code JavaScript à un composant spécialement conçu à cet effet. Nous pouvons ajouter un fichier JavaScript pour notre composant <Rental::Image> en exécutant le générateur de composants:


 $ ember generate component-class rental/image installing component-class create app/components/rental/image.js 

Cette commande a généré un fichier JavaScript portant le même nom que notre modèle de composant dans app/components/rentals/image.js . Il contient une classe JavaScript héritée de @glimmer/component .


Zoé explique ...



@glimmer/component ou Glimmer component est l'une des nombreuses classes de composants disponibles pour utilisation. Ils constituent un excellent point de départ lorsque vous souhaitez ajouter un comportement à vos composants. Dans ce didacticiel, nous n'utiliserons que des composants Glimmer.

En général, les composants Glimmer doivent être utilisés dans la mesure du possible. Cependant, vous pouvez également voir @ember/components (composants classiques) utilisés dans les anciennes applications. Vous pouvez les distinguer les uns des autres en regardant le chemin pour les importer (ce qui est utile lors de la recherche de la documentation appropriée, car ils ont des API différentes et incompatibles ).

Ember instancie la classe chaque fois que notre composant est appelé. Nous pouvons utiliser cette instance pour stocker notre état:



Ici, dans le constructeur du composant , nous avons initialisé la variable d'instance this.isLarge avec la valeur false , car il s'agit de l'état par défaut que nous voulons pour notre composant.


Accéder aux états d'instance à partir de modèles


Mettons à jour notre modèle pour utiliser cet état que nous venons d'ajouter:



Dans le modèle, nous avons accès aux variables d'instance du composant. La syntaxe conditionnelle {{#if ...}}...{{else}}...{{/if}} vous permet d'afficher un contenu différent selon la condition (dans ce cas, la valeur de la this.isLarge instance this.isLarge ). En combinant ces deux fonctions, nous pouvons respectivement visualiser à la fois une petite et une grande version de l'image.


Nous pouvons le vérifier en modifiant temporairement la valeur initiale dans notre fichier JavaScript. Si nous modifions app/components/rental/image.js pour initialiser this.isLarge = true ; dans le constructeur, nous devrions voir une grande version de l'image de propriété dans le navigateur. Ouah!



Après avoir vérifié, nous pouvons changer this.isLarge en false .


Étant donné que ce modèle d'initialisation pour les variables d'instance dans le constructeur est assez courant, il existe une syntaxe beaucoup plus courte:



Même fonctionnalité, mais beaucoup plus court!


Bien sûr, nos utilisateurs ne peuvent pas modifier notre code source, nous avons donc besoin d'un moyen de changer la taille de l'image à partir du navigateur. En particulier, nous voulons basculer la valeur de this.isLarge chaque fois qu'un utilisateur clique sur notre composant.


Gestion des états à l'aide de propriétés suivies


Modifions notre classe en ajoutant une méthode pour changer la taille:



Nous avons fait quelques choses ici, alors essayons de comprendre.


Tout d'abord, nous avons ajouté le décorateur @tracked à la isLarge instance @tracked . Cette annotation indique à Ember de garder une trace de cette variable pour les mises à jour. Chaque fois que la valeur de cette variable change, Ember redessine automatiquement tous les modèles qui dépendent de sa valeur.


Dans notre cas, chaque fois que nous this.isLarge une nouvelle valeur à this.isLarge , l'annotation this.isLarge @tracked Ember à surestimer la condition {{#if this.isLarge}} dans notre modèle et à basculer entre les deux blocs, respectivement.


Zoé explique ...



Ne t'inquiète pas! Si vous faites référence à une variable dans le modèle, mais que vous avez oublié d'ajouter le décorateur @tracked , en mode développement, vous obtiendrez une erreur claire lors de la modification de sa valeur!

Nous traitons les actions des utilisateurs


Ensuite, nous avons ajouté la méthode toggleSize à notre classe, qui commute this.isLarge par opposition à son état actuel ( false devient true ou true devient false ).


Enfin, nous avons ajouté le décorateur @action à notre méthode. Cela indique à Ember que nous avons l'intention d'utiliser cette méthode à partir de notre modèle. Sans cela, la méthode ne fonctionnerait pas correctement en tant que fonction de gestion des événements (dans ce cas, un gestionnaire de clics).


Zoé explique ...



Si vous oubliez d'ajouter le décorateur @action , vous obtiendrez également une erreur lorsque vous cliquez sur le bouton en mode développement!

Il est maintenant temps d'utiliser ceci dans le modèle:



Nous avons changé deux choses.


Tout d'abord, comme nous voulions rendre notre composant interactif, nous avons changé la balise conteneur de <div> à <button> (c'est important pour des raisons d'accessibilité). En utilisant la bonne balise sémantique, nous obtiendrons également une mise au point et une interaction clavier «gratuites».


Ensuite, nous avons utilisé le modificateur {{on}} pour attacher this.toggleSize tant que gestionnaire de clic de bouton.


Ainsi, nous avons créé notre premier composant interactif. Essayez comment cela fonctionne dans le navigateur!



Test d'interaction avec l'utilisateur


Enfin, écrivons un test pour ce nouveau comportement:




Résultat du test


Nettoyons notre modèle avant de continuer. Nous avons ajouté beaucoup de doublons lorsque nous avons inséré des expressions conditionnelles dans le modèle. Si nous regardons de près, les seules choses qui diffèrent entre ces deux blocs sont:
1) La présence d'une "large" classe CSS dans <button> .
2) Le texte «» et «» .


Ces modifications sont cachées dans de nombreux codes en double. Nous pouvons réduire la duplication en utilisant l'expression {{if}} place:



La version de l'expression {{if}} prend deux arguments. Le premier argument est la condition . Le deuxième argument est une expression, qui doit être exécutée si la condition est vraie.


Facultativement, {{if}} peut prendre comme troisième argument une expression qui doit être exécutée si la condition est fausse. Cela signifie que nous pourrions réécrire le libellé du bouton comme suit:



Que ce soit une amélioration de la clarté de notre code est une question de goût. Dans tous les cas, nous avons considérablement réduit la duplication de notre code et rendu plus visibles d'importants éléments de logique.


Exécutez les tests pour la dernière fois pour vous assurer que notre refactoring n'a rien cassé, et nous serons prêts pour le prochain défi!



Réutilisation des composants


La partie non réalisée restante du composant est une carte montrant l'emplacement de la maison, sur laquelle nous continuerons de travailler:


Lors de l'ajout d'une carte, vous découvrirez:


  • Gestion de la configuration au niveau de l'application
  • Paramétrage des composants avec des arguments
  • Accès aux arguments des composants
  • Interpolation de valeurs dans des modèles
  • Substitution des attributs HTML dans ... les attributs
  • Refactoring avec getters et auto-tracking (auto-track)
  • Récupération des valeurs JavaScript dans un contexte de test

Gestion de la configuration au niveau de l'application


Nous utiliserons l' API Mapbox pour créer des cartes pour nos propriétés locatives. Vous pouvez vous inscrire gratuitement et sans carte de crédit.


Mapbox fournit une API d' image de carte statique qui sert des images de carte au format PNG. Cela signifie que nous pouvons générer l'URL appropriée pour les paramètres que nous voulons et afficher la carte en utilisant le <img> standard. Classe!


Si vous êtes intéressé, vous pouvez explorer les options disponibles dans Mapbox à l'aide d' un sandbox interactif .


Après vous être inscrit auprès du service, prenez votre jeton public (jeton public par défaut) et collez-le dans config/environment.js :




Comme son nom l'indique, config/environment.js utilisé pour configurer notre application et stocker des clés API comme celles-ci. Ces valeurs sont accessibles à partir d'autres parties de notre application et peuvent avoir des valeurs différentes selon l'environnement actuel (qui peut être le développement, les tests (test) ou la production (production)).


Zoé explique ...



Si vous le souhaitez, vous pouvez créer différents jetons d'accès Mapbox à utiliser dans différents environnements. Au minimum, chaque jeton doit avoir une portée «styles: mosaïque» pour utiliser l'API Mapbox Static Image.

Après avoir enregistré les modifications dans notre fichier de configuration, nous devrons redémarrer notre serveur de développement pour recevoir ces modifications de fichier. Contrairement aux fichiers que nous avons modifiés, config/environment.js ne redémarre pas automatiquement.


Vous pouvez arrêter le serveur en trouvant la fenêtre du terminal où le ember server cours d'exécution, puis appuyez sur Ctrl + C C'est-à-dire en appuyant sur la touche «C» du clavier tout en maintenant enfoncée la touche «Ctrl». Une fois qu'il s'est arrêté, vous pouvez le redémarrer à l'aide de la même commande ember server .


 $ ember server building... Build successful (13286ms) – Serving on http://localhost:4200/ 

Création d'un composant contenant une classe de composants


Après avoir ajouté la clé API Mapbox à l'application, générons un nouveau composant pour notre carte.


 $ ember generate component map --with-component-class installing component create app/components/map.js create app/components/map.hbs installing component-test create tests/integration/components/map-test.js 

Étant donné que tous les composants ne sont pas nécessairement associés à un comportement spécifique, le générateur de composants ne crée pas par défaut de fichier JavaScript pour nous. Comme nous l'avons vu précédemment, nous pouvons toujours utiliser le générateur de composants pour l'ajouter ultérieurement.


Cependant, dans le cas de notre composant <Map> , nous sommes à peu près sûrs que nous aurons besoin d'un fichier JavaScript pour un comportement que nous n'avons pas encore défini! Par conséquent, nous pouvons passer l'indicateur --with-component-class générateur de --with-component-class afin d'avoir tout ce dont nous avons besoin dès le début.


Zoé conseille ...



Trop à taper? Utilisez la commande ember g component map -gc . L'indicateur -gc désigne le composant Glimmer ( g limmer c omponent), et génère également la classe ( g enerate c lass)

Paramétrage des composants à l'aide d'arguments


Commençons par notre fichier JavaScript:



Ici, nous importons le jeton d'accès à partir du fichier de configuration et le renvoyons à partir du token getter. Cela nous permet d'accéder à notre jeton en tant que this.token fois dans la classe MapComponent et dans le modèle de composant. Il est également important de coder le jeton, au cas où il contient des caractères spéciaux qui ne sont pas sûrs pour l'URL.


Interpolation des valeurs dans les modèles


Passons maintenant du fichier JavaScript au modèle:



Tout d'abord, nous avons un élément conteneur pour le style.


Ensuite, nous avons <img> pour demander et rendre une image de carte statique à partir de Mapbox.


Notre modèle contient plusieurs valeurs qui n'existent pas encore - @lat , @lng , @zoom , @width et @height . Ce sont les arguments du composant <Map> que nous lui fournirons lors de son appel.


En paramétrant notre composant avec des arguments, nous avons créé un composant réutilisable qui peut être appelé à partir de différentes parties de l'application et personnalisé pour répondre aux besoins de ces contextes spécifiques. Nous l'avons déjà vu en action lors de l'utilisation du composant <LinkTo> plus tôt; nous devions spécifier l'argument @route qu'il sache à quelle page aller.


Nous avons fourni une valeur par défaut raisonnable pour l'attribut alt fonction des valeurs des @lng @lat et @lng . Vous remarquerez peut-être que nous interpolons directement les valeurs dans la valeur de l'attribut alt . Ember combinera automatiquement ces valeurs interpolées en une valeur de chaîne, y compris l'exécution de tout code HTML d'échappement nécessaire.


Substitution des attributs HTML en ...attributes


Ensuite, nous avons utilisé ...attributes pour permettre à l'appelant de personnaliser davantage <img> , par exemple, de passer des attributs supplémentaires tels que la class et de remplacer notre attribut alt par défaut par un attribut plus spécifique ou plus convivial.


L'ordre est important! Ember applique les attributs dans l'ordre dans lequel ils apparaissent. En attribuant à l'attribut la valeur alt par défaut en premier (avant d'appliquer les ...attributes ), nous fournissons explicitement à l'appelant la possibilité de fournir un attribut alt plus spécialisé conformément au cas d'utilisation nécessaire.


Puisque l'attribut alt passé (s'il en existe un) apparaîtra après le nôtre, il remplacera la valeur que nous avons spécifiée. D'un autre côté, il est important que nous attribuions des attributs src , width et height after ... afin qu'ils ne soient pas accidentellement remplacés par l'invocateur.


L'attribut src interpole tous les paramètres nécessaires dans le format URL de l'API d' image statique Mapbox, y compris le jeton sûr URL this.token .


Enfin, puisque nous utilisons l'image @2x "rétine", nous devons spécifier les attributs width et height . Sinon, le <img> sera affiché deux fois plus que ce que nous attendions!


Nous avons ajouté pas mal de code à un composant, alors écrivons quelques tests! En particulier, nous devons nous assurer que nous avons une couverture de test pour le comportement des attributs HTML remplacés, dont nous avons discuté ci-dessus.





Notez que le hasAttribute aide hasAttribute de qunit-dom prend en charge l'utilisation d' expressions régulières . , , src https://api.mapbox.com/ ( , ). , , .


… .



, ! , ? , <Map> <Rental> :



!



...



, , config/environment.js MAPBOX_ACCESS_TOKEN . ! , Ember-.

<Rental> , <Map> .



- (auto-track)


<Map> src <img> , . — JavaScript .


JavaScript API this.args.* . , URL .


...



this.args — API, Glimmer. (, «» ) (legacy) , API JavaScript .



! !



, @tracked . , , Ember .


, , , . , src lat , lng , width , height zoom this.args . , , , {{this.src}} .


Ember , . @tracked , Ember , (invalidate) , «» . (auto-track). , this.args ( , this.args.* ), @tracked Glimmer. , (Just works).


JavaScript


, :





API this.setProperties , .


, . ( !).


this , render . «» . .


!




<Rental> . , :



:


  • (model hook)
  • (mocking) JSON
  • (remote)
  • {{#each}}


<Rental> . , , , , . .


, , . , .


, Ember — . , , .


. app/routes/index.js :



, , . Route . , .


Route IndexRoute, , .



. ? model() . .


, . Ember , . , , ( ).


, . , async . await . ( : , Promise Javascript )


. , , JavaScript ( POJO (Plain Old Javascript Object)).


, , , . @model . POJO, .


, , title :



, .



Super!


, , , , , ! <Rental> , .


.


-, <Rental> @rental . <h1> , , :



@model <Rental> @rental , «Grand Old Mansion» <Rental> ! , @rental .




, «Grand Old Mansion», , .



, : , .


, , , , .


<Rental> . , setProperties , .



, <Rental> render @rental . , !



(mocking) JSON


, , , , , !


, , , API. , API . JSON . , JSON HTTP- — , API, — - . Cool!


? , JSON .zip. public .


, public :


 public ├── api │ ├── rentals │ │ ├── downtown-charm.json │ │ ├── grand-old-mansion.json │ │ └── urban-living.json │ └── rentals.json ├── assets │ └── images │ └── teaching-tomster.png └── robots.txt 4 directories, 6 files 

, , URL http://localhost:4200/api/rentals.json .



«» JSON. !


(remote)


. , .



?


, Fetch API JSON API /api/rentals.json , URL, .


, . Fetch API , fetch async , . , await .


Fetch API . , ; , JSON, json() . , await .



, , .




JSON:API , , .


-, JSON:API , "data" , . ; , , , — , .


, , . type id , (!). , , attributes .


, , , , : , , type , - . type "Standalone" "Community", , <Rental> .


JSON:API. .


:



(parsing) JSON attributes , type , . , , - .


! .


(helper) {{#each}}


, , — index.hbs , <Rental> . @rental @model . , @model — ()! , , .


.



{{#each}}...{{/each}} , . — — . — <Rental> , <li> .


{{rental}} . rental ? , ! as |rental| each . - , as |property| , {{property}} .


, .



Hourra! , . fetch . , ?


, !



( 1.1 1.2)


Ember!


Ember, .


#Emberjs. Discord , ember_js


À votre retour, nous nous appuierons sur ce que nous avons appris dans la première partie et passerons à un nouveau niveau!


MISE À JOUR: Et la démolition remercie l'utilisateur MK1301 pour la correction d'erreur.

Source: https://habr.com/ru/post/fr482390/


All Articles