Tutoriel Backbone.js : les tâches

Alex Young

Traducteur

vermine

Cet article est la traduction de Backbone.js Tutorial: Tasks publié sur DailyJS.
Commentez ♪

- Titre : Tutoriel Backbone.js : les tâches

- Auteur : Alex Young

- Traducteur : vermine

- Parution : 14 février 2013

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2012 Alex Young. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Préparation

- II. Tâches CRUD

- III. Mise en place

- IV. Les vues

- V. Styles

- VI. Backbone 0.9.10

- VII. Résumé

- VIII. Remerciements

I - Préparation

- Partie 1 : environnement de développement

- Partie 2 : les API Google et RequireJS

- Partie 3 : authentification avec OAuth2

- Partie 4 : Backbone.sync

- Partie 5 : affichage des listes

- Partie 6 : créer des listes

- Partie 7 : modifier des listes

- Partie 8 : supprimer des listes

- Partie 9 : les tâches

- Partie 10 : oh non, pas plus de tâches

- Partie 11 : Spies, Stubs et Mocks

- Partie 12 : tester avec Mocks

- Partie 13 : routage

- Partie 14 : personnaliser l'interface

- Partie 15 : mettre à jour, purger

- Partie 16 : plugin jQuery et déplacement des tâches

Avant de commencer ce tutoriel, vous aurez besoin de ce qui suit :

- alexyoung/dailyjs-backbone-tutorial en version 8d88095 ;

- la clé de l'API de la partie 2 ;

- l'ID client de la partie 2 ;

- la mise à jour de app/js/config.js avec vos clés.

Pour consulter la source, exécutez les commandes suivantes (ou utilisez un outil approprié pour Git GUI) :

git clone git@github.com:alexyoung/dailyjs-backbone-tutorial.git
cd dailyjs-backbone-tutorial
git reset --hard 8d88095

II - Tâches CRUD

Les choses ont été calmes dans le projet Tasks Bootstrap au cours de ces dernières semaines. Les listes sont apparues, mais il manque un air de Hamburglar ou de Burger King en vue. Comment attirer toutes ces mascottes importantes de fast food à notre projet ? En ajoutant la prise en charge des tâches bien sûr ! Sinon, comment peuvent-ils écrire leurs listes exhaustives des inspections de la franchise ainsi que parler de l'édition spéciale McRibs ?

Ce tutoriel couvre les éléments suivants :

- création d'une vue pour une tâche ;

- création d'une vue pour une liste de tâches ;

- ajout de tâches à la collection ;

- extraction des tâches de l'API de Google.

La partie vraiment intéressante dont vous voudrez vous souvenir traite de la relation entre une vue parent et les vues enfants. Backbone ne dresse pas spécifiquement des relations entre modèles ou entre vues. Dans cet exemple, nous voulons idéalement dire aux tâches qu'elles appartiennent à des listes ou que les affichages des tâches appartiennent à des affichages de listes. Cependant, il n'existe pas une manière de facto d'exprimer de telles relations. Il existe des bibliothèques pour le faire, mais je vais vous montrer comment penser les choses en Backbone/Underscore.

III - Mise en place

Avant de commencer, créez quelques nouveaux répertoires :

$ mkdir app/js/views/tasks
$ mkdir app/js/templates/tasks

Et ajoutez une nouvelle collection au fichier app/js/collections/tasks.js:

define(['models/task'], function(Task) {
var Tasks = Backbone.Collection.extend({
model: Task,
url: 'tasks'
});

return Tasks;
});

La collection Tasks ne fait rien que vous n'ayez vu avant. Chercher des tâches à l'aide de l'API de Google nécessite tasklist, vous devez donc appeler fetch avec un paramètre supplémentaire :

collection.fetch({ data: { tasklist: this.model.get('id') }, // ...

C'est cool, parce que nous avons traité l'extraction de TaskLists comme ça quand nous avons passé { userId: '@me' } donc ça reste cohérent dans le cadre de ce projet.

Le template qui contient l'affichage des tâches comprend un formulaire permettant de créer de nouvelles tâches, un conteneur pour la liste des tâches et un autre conteneur pour la tâche actuellement sélectionnée (donc elle peut être modifiée). Ce fichier doit être enregistré sous app/js/templates/index.js:

<div class="span6">
<div id="add-task">
<form class="well row form-inline add-task">
<input type="text" class="pull-left" placeholder="Encodez un nouveau nom de tâche et appuyez sur Enter" name="title">
<button type="submit" class="pull-right btn"><i class="icon-plus"></i></button>
</form>
</div>
<ul id="task-list"></ul>
</div>
<div class="span6">
<div id="selected-task"></div>
<div class="alert" id="warning-no-task-selected">
<strong>Note :</strong> sélectionnez une tâche pour la modifier ou la supprimer.
</div>
</div>

Celui-ci utilise des classes Bootstrap pour créer des colonnes. Le TaskView, dans app/js/templates/tasks/task.html, a quelques éléments pour contenir le titre, des notes et une case à cocher pour la sélection/désélection de la tâche :

<input type="checkbox" data-task-id="" name="task_check_" class="check-task" value="t">
<span class="title "></span>
<span class="notes"></span>

IV - Les vues

La TasksIndexView principale charge les tâches à l'aide de la collection Tasks et les restitue ensuite à l'aide de TaskView. Il s'agit de la source de TasksIndexView dans le fichier app/js/views/tasks/index.js:

define(['text!templates/tasks/index.html', 'views/tasks/task', 'collections/tasks'], function(template, TaskView, Tasks) {
var TasksIndexView = Backbone.View.extend({
tagName: 'div',
className: 'row-fluid',

template: _.template(template),

events: {
'submit .add-task': 'addTask'
},

initialize: function() {
this.children = [];
},

addTask: function() {
},

render: function() {
this.$el.html(this.template());

var $el = this.$el.find('#task-list')
, self = this;

this.collection = new Tasks();
this.collection.fetch({ data: { tasklist: this.model.get('id') }, success: function() {
self.collection.each(function(task) {
var item = new TaskView({ model: task, parentView: self });
$el.append(item.render().el);
self.children.push(item);
});
}});

return this;
}
});

return TasksIndexView;
});

Ceci charge les tâches à l'aide de collection.fetch et ajoute ensuite un TaskView pour chaque tâche. Voici TaskView:

define(['text!templates/tasks/task.html'], function(template) {
var TaskView = Backbone.View.extend({
tagName: 'li',
className: 'controls well task row',

template: _.template(template),

events: {
'click': 'open'
},

initialize: function(options) {
this.parentView = options.parentView;
},

render: function(e) {
var $el = $(this.el);
$el.data('taskId', this.model.get('id'));
$el.html(this.template(this.model.toJSON()));
$el.find('.check-task').attr('checked', this.model.get('status') === 'completed');

return this;
},

open: function(e) {
if (this.parentView.activeTaskView) {
this.parentView.activeTaskView.close();
}
this.$el.addClass('active');
this.parentView.activeTaskView = this;
},

close: function(e) {
this.$el.removeClass('active');
}
});

return TaskView;
});

La vue parente est surveillée donc open peut déterminer si une autre tâche a été sélectionnée et, le cas échéant, « désactiver » la tâche précédente (supprimer la classe active). Il existe plusieurs façons de le faire. J'ai vu des gens itérer sur des vues pour les fermer toutes à l'aide de $('selector').removeClass('active') pour supprimer tous les objets disposant d'une classe active, ou bien déclencher des événements sur les modèles. J'estime que le code lié à la vue doit être géré dans la vue. Les modèles et les collections devraient faire leurs propres jobs.

Ensuite, vous devrez ajouter TasksIndexView dans le define du fichier app/js/views/lists/menuitem.js et modifier la méthode open pour instancier une TasksIndexView:

open: function() {
if (bTask.views.activeListMenuItem) {
bTask.views.activeListMenuItem.$el.removeClass('active');
}

bTask.views.activeListMenuItem = this;
this.$el.addClass('active');

// Afficher les tâches
if (bTask.views.tasksIndexView) {
bTask.views.tasksIndexView.remove();
}

bTask.views.tasksIndexView = new TasksIndexView({ collection: bTask.collections.tasks, model: this.model });
bTask.views.app.$el.find('#tasks-container').html(bTask.views.tasksIndexView.render().el);

return false;
}

Cela permet de suivre la dernière instance de TasksIndexView donc il peut la supprimer manuellement. C'est généralement une bonne idée d'appeler remove, car les événements peuvent donc être indépendants avant que les vues ne soient hors de portée. Je vais écrire un tutoriel sur Backbone et la collection garbage par la suite.

J'ai aussi ajouté quelques valeurs par défaut pour le modèle Task (dans le fichier app/js/models/task.js) :

define(function() {
var Task = Backbone.Model.extend({
url: 'tasks',
defaults: { title: '', notes: '' }
});

return Task;
});

La raison pour laquelle je fais cela est que TaskView déclenche des erreurs lorsque l'interpolation utilise un modèle qui n'a pas un titre ou des notes, ce qui est assez fréquent pour les tâches de Google Tasks.

Avec ces templates, ces vues et ces modifications, vous devriez être en mesure de sélectionner des listes et d'afficher leurs tâches, mais également de sélectionner les tâches.

V - Styles

En l'état, l'application n'a aucun attrait visuel. J'ai ajouté Bootstrap, il faut simplement télécharger les fichiers CSS et les images et les placer respectivement dans app/css et dans app/img. En outre, app/index.html charge css/bootstrap.min.css.

J'ai ajouté quelques styles personnalisés pour créer une disposition en layout qui affiche les tâches de façon similaire aux Things.

VI - Backbone 0.9.10

J'ai mis à jour Backbone pour avoir sa version 0.9.10 et je l'ai ajouté au répertoire. J'ai dû changer la méthode Backbone.sync pour utiliser une signature différente lorsque vous appelez options.success dans le fichier app/js/gapi.js:

options.success(model, result, request);

VII - Résumé

Le code source de ce tutoriel se trouve ici : alexyoung/dailyjs-backbone-tutorial en version 0491ad.

VIII - Remerciements

Cet article a été publié avec l'aimable autorisation de Alex Young concernant l'article original Backbone.js Tutorial: Tasks du site DailyJS.
Je remercie également _Max_ pour sa relecture attentive et assidue.