BT
x Votre opinion compte ! Merci de bien vouloir répondre au sondage InfoQ concernant vos habitudes de lecture !

Ember.js: pour des Applications Web Riches !

Écrit par Joachim Haagen Skeie , traduit par Olivier Gonthier le 23 mars 2012 |

Ember.js vient du projet SproutCore. Si cela ne vous dit rien, il s'agit d'un framework Modèle-Vue-contrôleur en JavaScript qui permet de réaliser des applications web riches semblables aux applications desktop, tant en termes d'utilisation qu'en termes de développement.

L'équipe de SproutCore ainsi que sa communauté ont longtemps travaillé sur SproutCore 2.0, finalement renommé en Ember.js. Pour plus d'informations sur cette transition, vous pouvez lire le blog de Yehuda Katz.

Bien que les deux frameworks aient la même origine, avec notamment un modèle objet et un système de template similaire, Ember.js a une vision très différente. Par différents aspects SproutCore essaye de cacher les codes HTML et CSS pour les développeurs, alors que Ember.js place HTML au centre de son modèle de développement. L'avantage du modèle de SproutCore étant qu'il sera plus facile d'appréhender le support de moteurs de rendu différents dans le futur (comme l'élément canvas de HTML5), ou encore d'appréhender le portage vers une application native. C'est une bonne idée, mais tout comme pour le projet JavaServer Faces (JSF), je n'ai jamais trouvé une seule application qui utilise autre chose que du HTML, CSS et JavaScript.

L'avantage du modèle d'Ember.js est que le HTML et la CSS sont facilement accessibles et contrôlables par le développeur tout en étant facile à adapter pour les différents besoins d'une application web. Cela nous mène donc au prochain point: Qu'est ce que Ember.js?

Ember.js, c'est quoi?

Selon le site officiel de Ember.js, c'est “a JavaScript framework for creating ambitious web applications that eliminates boilerplate and provides a standard application architecture”. (un framework JavaScript fait pour créer des applications web ambitieuses, qui évite les répétitions et fournit une architecture applicative standard)

Pour moi, Ember.js est un framework permettant de développer des applications internet riches (RIA) de façon convenable. Il prend ses racines dans les langages qui ont construit notre expérience du web(HTML, CSS et bien entendu JavaScript), ce qui aide les développeurs à conserver un code clair, propre, avec les forces du MVC. Il conserve tout de même les points forts de SproutCore: un modèle objet riche, un système de templating capable de se mettre à jour automatiquement, un binding puissant et cohérent, supportant des vues riches avec une gestion d'événements, mais encore de nombreux addons complémentaires, dont certains que j'aborderai dans la suite de cet article.

Le code source de Ember.js est disponible sur GitHub et les addons sont disponibles dans le dépôt ember-addons.. Cet article parlera plus précisemment de trois addons, Ember data, ainsi que sproutcore-statecharts et sproutcore-touch dans une version adaptée à Ember.js.

Configuration et structure du projet

Dans cet article nous allons développer une application de visualisation de photos, comprenant des miniatures sous forme de liste horizontale. Quand ces images sont cliquées, l'image sélectionnée sera affichée. L'application aura les fonctionnalités play et pause pour gérer un diaporama, et des boutons next et previous pour pouvoir naviguer dans les images. A la fin de l'article nous ajouterons un chargement dynamique des images depuis un fichier json, et le support des événements touch pour les supports qui le permettent. En particulier, les gestes tap, pinch(pincement), swipe(glissement) et pan(déplacement) seront implémentés.

Le code source de cette application est disponible sur GitHub. En général j'utilise IntelliJ IDEA comme IDE pour mes développements avec Ember.js ou SproutCore. Vous trouverez un fichier Maven pom.xml dans le dépôt: celui-ci est principalement là pour mon confort, afin d'importer facilement et proprement mon projet dans Intellij. Vous n'avez donc pas besoin d'en tenir compte, sachez simplement que tout le code source se trouve dans le dossier src/main/webapp. Si vous n'êtes pas familiers à Maven, ne prêtez pas attention à cette organisation, vous pouvez directement utiliser ce qui se trouve dans ce dossier.

L'application d'exemple aura au total trois librairies JavaScript en supplément de Ember version 0.9.4:

Si vous clonez le repo Ember-Example, ces dépendances sont déjà incluses, prêtes à être utilisées.

Si vous voulez partir de zéro en suivant cet article, vous pouvez toujours télécharger ces dépendances depuis GitHub.

Je posterais les exemples de code de cet article sous forme d'images. En plus de celles-ci, je référencerais également le fichier sur GitHub pour que vous puissiez copier et coller le contenu du fichier.

introduction aux bindings

Les bindings sont utilisés pour synchroniser les valeurs des variables entre les objets. Prenons un exemple:

Figure 0 - Exemple simple de Binding

Les lignes 15 à 23 créent une nouvelle application Ember.js appelée BindingsExamples. Celle-ci définit deux objets: BindingsExample.Person et BindingsExample.Car. La propriété name de l'objet Person a pour valeur la chaîne “Joachim Haagen Skeie”. En regardant l'objet Car, vous noterez qu'il a une propriété appelée "ownerBinding". Du fait que son nom se termine par "Binding", Ember.js va automatiquement créer une propriété "owner", qui est liée à la valeur d'une autre propriété, ici BindingsExample.Person.name.

Si vous ouvrez ce fichier HTML dans votre navigateur, cela affichera simplement la valeur de la propriété BindingsExample.Car.owner, soit “Joachim Haagen Skeie” dans ce cas.

L'avantage de cette approche est qu'à chaque changement effectué sur la propriété BindingsExample.Person.name, le contenu visible sur cette page sera également mis à jour. Essayez de taper ce qui suit dans la console de votre navigateur pour observer ce comportement:

BindingsExample.Person.set('name', 'Some random dude')

La page affichera à présent la chaîne "Some random dude". Maintenant que nous avons vu ce concept, nous pouvons nous attaquer à la réalisation de notre application.

Démarrer avec votre application Ember

Pour commencer, nous allons créer un fichier index.html vide, et ajouter les dossiers app, css, img et scripts. Le résultat final est visible ci-dessous:

Figure 1 – Structure du projet

Dans le dossier app, créez 4 fichiers vides avec les noms suivants:

  • app.js
  • main.js
  • stateManager.js
  • fixtureData.js

Dans le dossier css, créez un unique fichier nommé:

  • master.css

Nous compléterons ces fichiers au fur et à mesure de l'avancement de cet article.

Commencons par notre fichier index.html. Nous allons simplement référencer nos scripts et notre fichier CSS, et ajouter un unique élément div qui contiendra toute la logique de notre application. Voici ce à quoi devrait ressembler le fichier:

Figure 2 – Notre fichier index.html initial

La première chose que l'on doit faire, c'est créer un namespace pour notre application, dans le script app.js. J'ai décidé de l'appeler EME (EMber-Example). Ajoutez la suite dans votre fichier app.js:

Figure 3 – namespace Ember-Example (EME)

Enfin, le dernier point avant de définir le modèle objet de notre application, est d'ajouter une base minimaliste à notre fichier CSS. Je souhaite que l'application ait un fond blanc, avec des coins arrondis, et également que la zone principale de l'application remplisse entièrement l'écran. Ajoutez la suite dans votre fichier css/master.css.

Figure 4 – CSS pour la zone principale de l'application

Définir le modèle objet avec Ember Data

A ce stade nous devons tout d'abord ajouter ember-data à notre liste de scripts dans le fichier index.html. Vous pouvez voir l'historique des commits sur GitHub si vous n'êtes pas sûrs de vous.

Dans app/app.js nous allons initialiser un datastore que nous utiliserons pour sauvegarder nos données. Nous l'appelerons EME.store.

Figure 5 – Création du Datastore

Pour cette application nous n'aurons besoin que d'un type d'objet – une photo – qui aura trois propriétés: un ID, un titre et une URL. Nous définissons notre modèle en étendant DS.Model. Ajoutez la suite dans app/main.js. Notez que nous utilisons le mot-clé extend plutôt que le create que nous avons utilisé jusqu'ici. J'ai tendance à penser à create comme synonyme de new et à extend comme synonyme de interface.

Figure 6 – Le modèle de l'objet Photo

La propriété "id" est utilisée comme clé primaire par défaut, ce qui est donc redondant par rapport à l'exemple ci-dessus. Je préfère le préciser tout de même car j'aime avoir une définition explicite de mes modèles.

Définition de contrôleurs et ajout de données de test

Notre application aura deux types de contrôleur, un qui contrôle l'enchaînement d'affichage de miniatures cliquables, et un qui affichera la photo courante. Dans app/main.js, je crée donc les deux contrôleurs EME.PhotoListController et EME.SelectedPhotoController.

Figure 7 – Définition des contrôleurs

Notez que le PhotoListController est de type Em.ArrayProxy, alors que le SelectedPhotoController est de type Em.Object. Vous remarquerez également que le contenu de SelectedPhotoController est lié à la propriété PhotoListController.selected en utilisant le suffixe Binding. A chaque fois que vous ajoutez ce suffixe au nom de vos propriétés, Ember.js assure que pour chaque changement de la valeur liée, votre propriété se mettra à jour automatiquement. Les bindings sont des composants clés de Ember.js, et une de ses plus grandes forces.

A cet instant, il peut être très pratique d'ajouter des données de tests, pour que l'on puisse avoir des choses à afficher lorsque nous définirons nos vues dans la prochaîne section.

Dans le dossier img, vous trouverez un set de 10 photos. Vous pouvez les utiliser pour le tutoriel mais elles ne sont pas prévues pour être redistribuées de quelque manière que ce soit.

Nous allons créer 10 objets Photo, un pour chaque photo se trouvant dans le répertoire img. Nous faisons cela dans notre fichier app/fixtureData.js.

Figure 8 – Données de test

Nous utilisons ici notre EME.store, que nous avons créé auparavant dans notre app.js, pour instancier de nouveaux objets EME.Photo. Chaque objet est initialisé avec les trois propriétés id, imageTitle et imageUrl.

Définir l'état des vues

Ember.js embarque un framework nommé Statechart. Celui-ci est basé sur le framework Statechart de SproutCore. L'implémentation du Statechart d'Ember.js est un peu plus simple en comparaison de ce que j'avais l'habitude d'utiliser avec SproutCore, et propose également une nouveauté très puissante: les ViewStates.

Si vous n'avez jamais utilisé Statechart auparavant, je vous invite à en lire plus sur le sujet sur le blog de SproutCore. Même si la structure est légèrement différente avec Ember.js, vous devriez être en mesure de faire le parallèle.

Notre StateChart est défini dans app/stateManager.js.

Figure 9 – State Manager

Je place ici le code du State Manager dans la fonction setTimeout(..., 50). C'est une habitude personnelle, mais ce n'est absolument pas nécessaire. Cependant j'aime cette manière de faire car cela me permet de vérifier plus simplement que j'ai correctement configuré mes bindings, ou que toute autre tâche asynchrone fait exactement ce que j'en attends.

Avant de définir l'object EME.stateManager, je m'assure que j'ai bien chargé mes données de test à la ligne 2.

La ligne 4 définit notre principal State Manager. Remarquez que la définition du rootElement à la ligne 5 définit sur quel élément du DOM le state manager est capable d'agir. A la ligne 6 nous définissons l'état initial à showPhotoView, qui est également le seul état dont on a besoin pour cette application.

Le code des lignes 9 à 12 est très important. Chaque état (ou ViewState) exécute une fonction à son passage - la fonction d'entrée - et une autre est exécutée quand on quitte cet état - la fonction de sortie. Ember.ViewState se chargera d'ajouter et de retirer la vue du DOM. Cela se réalise au moyen des fonctions d'entrée et de sortie, c'est pourquoi il est important d'appeler this._super(); à la ligne 10 afin de ne pas surcharger cette fonctionnalité. A la ligne 11 nous mettons à jour le contenu du PhotoListController pour chaque objet EME.Photo présent dans le datastore EME.store.

Chaque ViewState a une propriété view qui définit le contenu qu'il doit ajouter ou enlever dans l'arbre du DOM. Dans notre application nous avons défini cette propriété de type Ember.ContainerView, ce qui signifie que c'est une vue capable de détenir plusieurs sous-vues. Il y a actuellement une seule sous-vue, la PhotoListView de type Ember.View.

Template des miniatures

Nous arrivons finalement au point où nous sommes capables de créer des vues qui affichent nos photos. Nous allons donc continuer avec l'affichage des vignettes miniatures. Nous allons utiliser Handlebars, le système de template qui fait partie d'Ember.js. Ajoutez le code suivant avant le dans index.html:

Figure 10 – Template de la liste de photos

Il y a de nouveaux éléments dans le code ci-dessus auxquels vous pourriez ne pas être familiers. Handlebars utilise Mustache comme base de template et tout ce qui se trouve entre {{ et }} fait partie de ces templates. La ligne 23 montre la structure d'un for each avec Handlebar. {{#each content}} veut dire que son contenu (avant {{/each}}) sera répété pour chaque item du template, dans ce cas une unique image. Notez que nous avons lié l'attribut src de img-tag à la propriété imageUrl. La dernière information importante ici est le data-template-name, auquel nous ferons référence dans notre ViewState.

Il reste deux étapes pour afficher notre liste de photos correctement. La première est de définir notre photoListView (app/stateManager.js) pour utiliser le template photo-view-list, et la seconde est de définir la CSS pour positionner et redimensionner les vignettes.

Ajouter la suite dans app/stateManager.js:

Figure 11 – photoListView

On peut ici faire quelques remarques. La première est le fait que nous définissons le contenu HTML de notre photoListView en indiquant à la vue d'utiliser le template photo-view-list. La seconde est la manière dont nous faisons le lien entre le contenu et notre variable EME.PhotoListController.content via la propriété contentBinding. A chaque fois que le contenu de notre PhotoListController changera, Ember.js s'assurera que la vue sera mise à jour également. Ça peut presque ressembler à de la magie mais vous vous accoutumerez rapidement à cette manière rapide et simple de lier vos vues et vos contrôleurs. Puisque nous n'avons pas spécifié une propriété tagName le contenu de la vue sera inclus dans un élément div. Nous avons cependant spécifié que l'attribut class de cet élément div est thumbnailViewList.

Ensuite nous devons définir quelques règles CSS pour les classes thumbnailViewList et thumbnailItem que nous avons définies auparavant. Ajoutez la suite au fichier css/master.css:

Figure 12 – CSS pourles miniatures

La CSS ci-dessus est assez simple. Nous plaçons la liste de miniatures en bas de l'écran, et chaque vignette occupe un espace de 75x75 pixels avec une marge de 10 pixels.

En rafraîchissant la page dans votre navigateur vous devriez obtenir le résultat suivant:

Figure 13 – résultat de l'ajout des miniatures

Afin de rendre nos vignettes cliquables, je recommande généralement de créer une vue pour l'image. Nous allons donc remplacer notre élément div de notre template avec une vue. Définissons EME.TumbnailPhotoView dans app/main.js:

Figure 14 – Définir une vue cliquable

Vous devriez commencer à vous habituer à ce code. Nous définissons une vue en étendant Ember.View, au sein de laquelle nous surchargeons la fonction click. Nous voulons que la propriété selected de EME.PhotoListController corresponde à chaque vignette sur laquelle on clique.

Enfin, nous devons mettre à jour le template que l'on utilise dans cette nouvelle vue. Modifiez le fichier index.html:

Figure 15 – Le template photo-list-view

Vous pouvez voir que nous avons modifié les lignes 24 à 26. Nous spécifions ici que nous voulons utiliser la vue EME.ThumbnailPhotoView, et nous lions chaque vue à this, ce qui veut dire que chaque photo aura son propre contenu. Nous avons donc changé le {{bindAttr src=...}} de imageUrl pour content.imageUrl. Vos miniatures sont maintenant cliquables et mettront à jour la propriété 'content' de EME.SelectedPhotoController.

Le template pour la photo sélectionnée

Lorsqu'une image est sélectionnée nous voulons afficher une version plus grande de l'image au dessus de la miniature. Commencons par définir un nouvelle vue dans notre fichier app/stateManager.js:

Figure 16 – Ajout de selectedPhotoView

Ici nous avons ajouté une nouvelle vue au contenueur Em.ContainerView que nous avions précédemment appelée selectedPhotoView. Le contenu de la vue est très similaire à celle que nous avons définie au dessus, et ne devrait pas nécessiter d'explications supplémentaires. Notez, toutefois, que nous avons ajouté la nouvelle vue au tableau childViews à la ligne 15.

Ensuite, nous devons définir le template selected-photo dans index.html:

Figure 17 – Template pour la photo sélectionnée

Ce template est très similaire à celui utilisé pour la liste de miniatures. Nous avons échangé {{#each}} par {{with}} puisque nous avons une seule image sélectionnée à la fois. Nous avons aussi créé une nouvelle vue EME.SelectedPhotoView (visible dans la figure 18) que nous utilisons pour y mettre la photo. A part cela, le code ci-dessus ne devrait pas nécessiter d'explications supplémentaires. Ajoutez la suite dans votre fichier app/main.js

Figure 18 – SelectedPhotoView

La seule chose qui nous manque encore est la définition de la feuille de style pour notre selectedPhotoItem. Ajoutez la suite dans le fichier css/master.css

Figure 19 – CSS pour la photo sélectionnée

Si vous rechargez la page dans votre navigateur et que vous cliquez sur une miniature, le résultat devrait être similaire à la figure 20 ci dessous.

Figure 20 – Le résultat après séléction d'une image

Afin de mieux visualiser quelle image est sélectionnée, nous devons ajouter un peu de style CSS. Idéalement, la photo sélectionnée sera affichée légèrement plus grosse que les autres miniatures et présentée avec une flêche pour mieux la distinguer.

Figure 21 – Après ajout de CSS pour visualisation de la photo sélectionnée

Vous pourrez trouver le code CSS nécessaire pour ces changements sur ce commit sur GitHub.

Ajout de boutons de contrôle

Nous allons maintenant ajouter quatre boutons de contrôle dessous la photo sélectionnée. Le bouton "Play" lancera un diaporama, et changera la photo sélectionnée toutes les 4 secondes. Le bouton "Stop" arrêtera le diaporama, et les boutons "Next" et "Prev" séléctionneront, respectivement, la photo suivante et la photo précédente. Commencons par ajouter une vue pour nos boutons dans le fichier app/stateManager.js.

Figure 22 – Ajout d'une vue pour les boutons

La code ci-dessus implique que nous devons définir un nouveau template control-button-view et une classe CSS controlButtons. Ajoutons donc ces changements dans index.html et css/master.css:

Figure 23 – Template pour les boutons

Dans ce code nous utilisons directement l'objet Ember.Button. Nous définissons une cible – Le contrôleur que nous voulons notifier lorsque le bouton est cliqué – et une action – la fonction de l'objet visé que nous voulons exécuter. Comme vous vous en doutez, notre PhotoListController devra implémenter ces 4 fonctions. Nous allons revenir sur cette implémentation un peu plus tard. Jetons d'abord un oeil à la CSS pour les boutons de contrôle:

Figure 24 – CSS pourles boutons

La CSS ci-dessus est assez simple. En rafraîchissant votre navigateur vous devriez obtenir le résultat suivant:

Figure 25 – Barre de boutons ajoutée

Commençons par l'action la plus compliquée, nextPhoto. Ajoutez la suite dans le fichier app/main.js:

Figure 26 – Action nextPhoto

L'action nextPhoto est implémentée comme une fonction dans notre EME.PhotoListController. Quand nous chargeons l'application dans notre navigateur, la propriété selected est nulle par défaut. Nous y remédions dans les lignes 25 à 27 en initialisant cette propriété au premier élément de notre tableau de photos. Ember.js va automatiquement étendre le tableau standard de JavaScript aux Enumerables d'Ember.js. Vous pouvez en lire plus à ce sujet dans la documentation, mais c'est en l'occurrence ce qui nous permet d'appeler get(‘firstObject’) sur notre tableau.

Les lignes 27 à 36 sont assez simples à comprendre. On commence par trouver l'index de la photo couramment sélectionnée dans notre tableau. Les lignes 30 à 34 permettent à la fonction nextPhoto de revenir à la première photo si l'utilisateur appuie sur le bouton next en ayant la dernière photo sélectionnée. Enfin, nous réaffectons la propriété selected du contrôleur à la ligne 36.

Le code des lignes 12 à 19 parcourt le contenu du tableau afin de trouver l'index de la photo sélectionnée.

Le code pour la fonction prevPhoto se trouve ci-dessous. Il est très similaire à celui de la fonction nextPhoto, je ne détaillerai donc pas son contenu.

Figure 27 – Action prevPhoto

Nous en venons maintenant à notre fonctionnalité diaporama. Comme vous le devinez peut-être, celle-ci utilisera la fonction nextPhoto. Nous aurons de plus besoin d'un timer afin d'appeler la fonction nextPhoto toutes les 4 secondes. Ajoutez la suite au début de votre EME.PhotoListController dans app/main.js:

Figure 28 – Diaporama

Lorsque l'on clique sur le bouton "start", nous voulons nous déplacer sur la photo suivante immédiatement. Puis nous voulons démarrer un timer qui appellera à nouveau la fonction nextPhoto toutes les 4 secondes. J'utilise simplement la fonction standard setInterval de JavaScript pour implémenter le timer. Il faut conserver l'identifiant du timer pour que le bouton "stop" soit capable de stopper le timer via la fonction clearInterval.

Il est maintenant temps de recharger notre application et de tester nos nouveaux boutons de contrôle.

Gestion d'événement Touch avec Ember Touch

Ember Touch est dérivé du projet SproutCore Touch. A l'origine celui-ci est disponible dans le dépôt emberjs-addons. Toutefois, depuis que SproutCore 2.0 est devenu Ember.js, le dépôt emberjs-addons n'a pas vraiment été maintenu. Pour remédier à ce problème, Nous allons utiliser le fork de SproutCore Touch fait par ppcano. Ce projet produit également un fichier ember-touch.js, et ajoute de nouveaux mouvements.

Il y a deux types de gestes tactiles, des gestes instantanés comme les 'tap' et les gestes non instantanés comme le swipe, le pinch et le zoom. La différence entre ces deux types de mouvements est la suivante: les gestes instantanés ne sont reconnus que par un événement, alors que ceux non-instantanés ont également des événements start, end et un dernier qui donne l'évolution du geste. Il est possible d'ajouter des animations pour les gestes swipe(glisser), pinch(pincer) et pan(déplacer).

La première chose que nous devons faire est désactiver le comportement par défaut du gestionnaire d'événements pour les supports tactiles. Autrement, les éléments HTML ne seraient pas capable de reconnaître les mouvements touch. Comme nous voulons que notre application soit entièrement compatible avec ces mouvements, nous modifions l'attribut ontouchmove de l'élément body de la page.

Nous allons ajouter les mouvements touch à notre EME.SelectedPhotoView. Commencons par ajouter les fonctionnalités swipe vers la gauche ou la droite pour séléctionner, respectivement, la photo suivante et la photo précédente. Ajoutons la suite dans le fichier app/main.js:

Figure 29 – Swipe

Nous commençons par définir les options applicables au swipe à la ligne 87. Nous avons défini le swipe pour qu'il nécéssite deux doigts, et nous voulons accepter le mouvement dans les directions gauche et droite. Comme nous ne voulons pas animer ce mouvement, nous surchargeons simplement la méthode swipeEnd. Si nous avions voulu changer l'animation, nous aurions aussi surchargé les fonctions swipeChange et/ou swipeStart.

Pour un glissé vers la gauche nous voulons afficher la photo suivante, et pour un glissé vers la droite nous voulons afficher la précédente. Ici nous réutilisons simplement les fonctions prevPhoto et nextPhoto que nous avions ajouté pour nos boutons précédents et suivants plus haut.

Maintenant, ajoutons la capacité de zoomer sur notre photo sélectionnée. Nous voulons animer le zoom pour faire un effet plus visuel et précis. Nous surchargeons donc la fonction pinchChange. Ajoutez la suite dans app/main.js:

Figure 30 – Pinch

Ici nous utilisons la librairie jquery.transit pour effectuer la mise à l'échelle de l'image. Le code devrait être assez simple. Lorsque notre 'pinch' évolue, la fonction pinchChange est appelée avec l'objet recognizer. Nous obtenons l'attribut scale avec cet objet et nous l'utilisons pour zoomer dans notre photo.

Notez que nous ne zoomons pas sur la vue elle même, mais plutôt sur l'élément avec l'ID "selectedImage". La prochaine étape est donc de l'ajouter à notre template selected-photo. Ajoutez l'attribut ID à la ligne 34 du fichier index.html:

Figure 31 – Ajout de l'id selectedImage

Maintenans que nous sommes capables de zoomer dans la photo sélectionnée, nous avons besoin de nous y déplacer. Sinon, nous ne serions pas capables de voir les bords de l'image en zoomant. Tout comme le geste pinch, nous voulons animer le geste pan. Ajoutez la suite dans app/main.js:

Figure 32 – Pan

Comme vous pouvez le voir nous définissons le mouvement pan pour qu'il soit exécuté avec un seul doigt. Tout comme pour le pinch, nous utilisons jquery.transit pour effectuer le déplacement dans l'image. Le code étrange des lignes 119 et 120 est ma facon de formater une chaîne de caractères qui commence par "+=" ou "-=". Ceci est nécessaire si vous ne voulez pas que l'image soit réinitialisée à chaque appel de la fonction panChange.

Connexion à une source de données d'un backend avec Ember Data

Comme nous n'avons pas un réel serveur pour y récupérer nos résultats, nous allons le reproduire simplement en créant un ficher nommé "photos" à la racine de notre webapp. Ce fichier contiendra du JSON qui simule la réponse de l'url "/photos". Le contenu de ce fichier est ci-dessous:

Figure 33 – Le fichier photos

Vous reconnaitrez sans doute le contenu du fichier app/fixtureData.js. Celui-ci n'est plus nécessaire, et il peut être supprimé. N'oubliez pas d'enlever l'appel à la fonction EME.generateImages dans app/stateManager.js:

Figure 34 – Suppression de l'appel à generateImages

La raison pour laquelle je montre à nouveau ici le code du stateManager est que nous devons revenir sur la ligne 10. Ici, nous appelons EME.store.findAll(EME.Photo)). Par défaut cette fonction va retourner tous les objets qui sont déjà chargés dans le data store. Comme nous ne générons plus de données de test, nous devons ajouter quelques lignes pour récupérer le contenu du fichier photo. Ouvrons app/app.js et ajoutons un peu de magie de Ember Data:

Figure 35 – Store Adapter

Nous avons ajouté quelques lignes de code dans notre objet EME.store pour pouvoir utiliser un Adapter personnalisé. Ember Data utilise cet adapter pour échanger avec le serveur et charger les objets venant du store. Pour notre application nous avons simplement besoin de surcharger la fonction findAll. Mais dans une vraie application, vous aurez sans doute également à surcharger find, findMany, createRecord, updateRecord, deleteRecord, commit etc. Pour une liste plus complète des fonctionnalités d'Ember Data, allez jeter un coup d'oeil à la documentation.

A la ligne 7 nous définisson notre classe EME.Adapter, qui possède une unique fonction, findAll. Celle-ci prend deux arguments, un store et un type, qui représente le type d'objet que nous recherchons. Ce type d'objet définit l'URL utilisée. Comme nous ne demandons par un ID spécifique ou un autre paramètre, nous pouvons simplement passer cette URL à jQuery.getJSON. A la ligne 15 nous chargeons les objets récupérés dans le store en utilisant la fonction loadMany.

Maintenant, vous vous demandez peut être comment notre classe Photo sait qu'elle va requêter l'URL du fichier photos. Rendons nous dans notre app/main.js et ajoutons quelques lignes:

Figure 36 – reopenClass

Vous devriez à présent pouvoir rafraichir votre navigateur et voir que les images sont bien chargées depuis notre fichier photos.

Habituellement je n'ajoute pas mon Adapter dans le fichier app.js, mais plutôt dans son propre fichier JavaScript. Cela simplifie l'accès au code de l'Adapater lorsque l'on veut changer son implémentation par la suite.

Conclusion

Pour moi Ember.js représente exactement la manière dont je veux développer des clients sous forme de web application. Ember.js est fortement couplé aux technologies qui construisent le web aujourd'hui, et je pense que c'est un plus qu'il n'essaye pas d'en faire abstraction. Lorsqu'un jour il y aura une migration de HTML à Canvas, ou toute autre technologie, je suis convaincu que le framework évoluera lui aussi avec les tendances des frontend web.

Ce que Ember.js apporte est un modèle de développement d'application propre et consistant. Il rend vraiment facile la création de votre propre composant, et les templates sont faciles à comprendre, créer et mettre à jour. Si on y ajoute la manière cohérente de gérer les bindings et les propriétés, Ember.js offre en fait une excellente base de code qu'un framework web doit avoir. Et comme il est très facile de voir quelle technologie est utilisée et comment l'arbre du DOM se met à jour, il est également facile d'y ajouter des add-ons et plugins.

J'espère que cet article vous aura donné une meilleure compréhension du modèle de développement d'Ember.js et que vous aurez maintenant une vision plus claire de comment vous pourrez utiliser Ember.js dans votre prochain projet. Et comme le titre de l'article le dit, je crois honnêtement que Ember.js est la bonne manière de faire des applications internet riches!

A propos de l'auteur

Joachim Haagen Skeie est co-directeur de Kantega AS à Oslo en Norvège. Il travaille comme consultant sur des technologies du Web et Java, avec un intérêt profond pour le profiling d'applications et l'Open-Source. Il peut être joint via Twitter ou via son Blog.

Bonjour étranger!

Vous devez créer un compte InfoQ ou cliquez sur pour déposer des commentaires. Mais il y a bien d'autres avantages à s'enregistrer.

Tirez le meilleur d'InfoQ

Donnez-nous votre avis

Html autorisé: a,b,br,blockquote,i,li,pre,u,ul,p

M'envoyer un email pour toute réponse à l'un de mes messages dans ce sujet
Commentaires de la Communauté

Html autorisé: a,b,br,blockquote,i,li,pre,u,ul,p

M'envoyer un email pour toute réponse à l'un de mes messages dans ce sujet

Html autorisé: a,b,br,blockquote,i,li,pre,u,ul,p

M'envoyer un email pour toute réponse à l'un de mes messages dans ce sujet

Discuter

Contenu Éducatif

Rien ne serait possible sans le soutien et la confiance de nos Sponsors Fondateurs:

AppDynamics   CloudBees   Microsoft   Zenika
Feedback Général
Bugs
Publicité
Éditorial
InfoQ.com et tous les contenus sont copyright © 2006-2014 C4Media Inc. InfoQ.com est hébergé chez Contegix, le meilleur ISP avec lequel nous ayons travaillé.
Politique de confidentialité
BT