Tutoriel Backbone.js : oh non, pas plus de tâches

Alex Young

Traducteur

vermine

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

- Titre : Tutoriel Backbone.js : oh non, pas plus de tâches

- Auteur : Alex Young

- Traducteur : vermine

- Parution : 21 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 ® 2013 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, la suite

- III. L'ajout de tâches

- IV. La modification de tâches

- V. La suppression de tâches

- VI. L'activation/désactivation de tâches

- 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 0491ad ;

- 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 0491ad

II - Tâches, la suite

L'application consiste maintenant en l'affichage des listes de tâches. Mais vous ne pouvez pas encore interagir avec elles. Ce tutoriel couvre :

- l'ajout de tâches ;

- la modification de tâches ;

- la suppression de tâches ;

- l'activation/désactivation de tâches.

La plupart de ces contenus s'appuient sur ce que nous avons fait avec les listes, mais c'est une bonne pratique si vous cherchez plus d'expérience avec Backbone.

III - L'ajout de tâches

Ouvrez le fichier app/js/views/tasks/index.js et ajoutez la gestion d'un événement pour addTask:

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

Dans la méthode initialize, ajoutez un écouteur à la collection de cette classe :

initialize: function() {
this.children = [];
this.collection.on('add', this.renderTask, this);
},

Cela affiche automatiquement les nouvelles tâches lorsqu'elles sont ajoutées à la collection.

La méthode addTask doit appeler Task.prototype.save pour faire persister la tâche à l'aide des API Google après son instanciation avec une référence à la liste actuelle. Cela devrait également afficher la tâche une fois qu'elle a été enregistrée. J'ai mis { at: 0} car Google Tasks place les nouvelles tâches en haut d'une liste. Notez que je préfère ajouter uniquement des tâches une fois qu'elles ont été enregistrées avec succès, ce qui fait que cette application nécessite toujours une connexion Internet. Il peut être préférable de faire un enregistrement dans une base de données locale et de synchroniser avec Google par la suite, mais nous n'allons pas faire cela ici.

collection.fetch({ data: { tasklist: this.model.get('id') }, // ...addTask: function() {
var $input = this.$el.find('input[name="title"]')
, task = new this.collection.model({ tasklist: this.model.get('id') })
, self = this
;

task.save({ title: $input.val() }, {
success: function() {
self.collection.add(task, { at: 0 });
}
});
$input.val('');

return false;
},

renderTask: function(task, list, options) {
var item = new TaskView({ model: task, parentView: this })
, $el = this.$el.find('#task-list');
if (options && options.at === 0) {
$el.prepend(item.render().el);
} else {
$el.append(item.render().el);
}
this.children.push(item);
},

La méthode renderTask reçoit l'argument options et l'utilise pour déterminer la façon d'ajouter la tâche à la liste. La raison pour laquelle je n'ajoute pas simplement de nouvelles tâches est que la méthode render peut maintenant être refactorisée pour utiliser cette méthode :

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

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

this.collection.fetch({ data: { tasklist: this.model.get('id') }, success: function() {
self.collection.each(function(task) {
task.set('tasklist', self.model.get('id'));
self.renderTask(task);
});
}});
}

Ouvrez le fichier app/js/views/lists/menuitem.js et faites passer la tâche dans une collection de Tasks au niveau de la méthode open où elle instancie bTask.views.tasksIndexView:

bTask.views.tasksIndexView = new TasksIndexView({ collection: new Tasks({ tasklist: this.model.get('id') }), model: this.model });

Vous aurez besoin de modifier l'instruction define en haut du fichier pour inclure la collection Tasks:

define(['text!templates/lists/menuitem.html', 'views/tasks/index', 'collections/tasks'], function(template, TasksIndexView, Tasks) {

En raison de la manière dont fonctionnent les API Google, vous aurez besoin de faire un petit changement au fichier app/js/gapi.js pour insérer un ID tasklist dans le requestContent:

Backbone.sync = function(method, model, options) {
var requestContent = {};
options || (options = {});

switch (model.url) {
case 'tasks':
requestContent.task = model.get('id');
requestContent.tasklist = model.get('tasklist');
break;

L'ajout de tâches devrait maintenant fonctionner. Il n'y a pas besoin d'un nouveau template parce qu'il a déjà été ajouté dans le cadre d'un tutoriel précédent.

IV - La modification de tâches

Pour modifier les tâches, certaines choses sont nécessaires :

- un template de formulaire approprié ;

- une Backbone.View;

- une gestion des événements pour enregistrer la tâche.

Voici le template qui doit être enregistré dans le fichier app/js/templates/tasks/edit.html:

<fieldset>
<legend>
Propriétés de la tâche
<a href="#" data-task-id="" class="pull-right delete-task btn"><i class="icon-trash"></i></a>
</legend>
<div class="control-group">
<label for="task_title">Titre</label>
<input type="text" class="input-block-level" name="title" id="task_title" value="" placeholder="Le titre de la tâche">
</div>
<div class="control-group">
<label class="radio"><input type="radio" name="status" value="needsAction" >Besoin d'actions</label>
<label class="radio"><input type="radio" name="status" value="completed" >Complété</label>
</div>
</div>
<div class="control-group">
<label for="task_notes">Informations</label>
<textarea class="input-block-level" name="notes" id="task_notes" placeholder="Informations à propos de cette tâche"></textarea>
</div>
</fieldset>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Enregistrer les modifications</button>
<button class="cancel btn">Fermer</button>
</div>

J'ai inclus toutes les classes Bootstrap habituelles et le balisage dans ce fragment de formulaire donc cela sera agréable à l'affichage.

La vue correspondante (app/js/views/tasks/edit.js) devrait ressembler à ceci :

define(['text!templates/tasks/edit.html'], function(template) {
var TaskEditView = Backbone.View.extend({
tagName: 'form',
className: 'well edit-task',
template: _.template(template),

events: {
'submit': 'submit'
, 'click .cancel': 'cancel'
},

initialize: function() {
this.model.on('change', this.render, this);
},

render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},

submit: function() {
var title = this.$el.find('input[name="title"]').val()
, notes = this.$el.find('textarea[name="notes"]').val()
, status = this.$el.find('input[name="status"]:checked').val()
;

this.model.set('title', title);
this.model.set('notes', notes);

if (status !== this.model.get('status')) {
this.model.set('status', status);
if (status === 'needsAction') {
this.model.set('completed', null);
}
}

this.model.save();
return false;
},

cancel: function() {
this.remove();
return false;
}
});

return TaskEditView;
});

Cela met en place un événement submit pour la capture de l'envoi du formulaire et également un événement pour la fermeture du formulaire, lequel est lié à la méthode cancel.

Maintenant, ajoutez une méthode au fichier app/js/views/tasks/index.js qui invoque TaskEditView:

editTask: function(task) {
if (this.taskEditView) {
this.taskEditView.remove();
}
this.taskEditView = new TaskEditView({ model: task });
this.$el.find('#selected-task').append(this.taskEditView.render().el);
}

Et assurez-vous qu'elle charge TaskEditView:

define(['text!templates/tasks/index.html', 'views/tasks/task', 'views/tasks/edit', 'collections/tasks'], function(template, TaskView, TaskEditView, Tasks) {

Cela doit être appelé par une tâche individuelle, donc ouvrez le fichier app/js/views/tasks/task.js et ajoutez ceci à la méthode open:

this.parentView.editTask(this.model);

Ces deux vues ont beaucoup de couplage entre elles, ce qui rend difficile la réutilisation de TaskView. Cependant, y a-t-il un sens à les utiliser sans TasksIndexView ? C'est le genre de question que vous allez vous poser en essayant d'écrire du code Backbone maintenable.

V - La suppression de tâches

Ajoutez une méthode destroy au fichier app/js/views/tasks/edit.js:

destroy: function() {
this.model.destroy();
return false;
}

Ensuite, liez la méthode à l'événement sur l'icône de la corbeille (.delete-task), puis liez un événement sur le modèle en cours de suppression :

events: {
'submit': 'submit'
, 'click .cancel': 'cancel'
, 'click .delete-task': 'destroy'
},

initialize: function() {
this.model.on('change', this.render, this);
this.model.on('destroy', this.remove, this);
},

VI - L'activation/désactivation de tâches

Voici la cerise sur le gâteau, activation/désactivation de la tâche ! Avec ce changement, l'application commencera vraiment à être une réelle application de liste de tâches. Ouvrez le fichier app/js/views/tasks/task.js et ajoutez une liaison d'événements pour les cases à cocher dans la liste. Un événement change est nécessaire pour cela :

events: {
'click': 'open'
, 'change .check-task': 'toggle'
},

Puis la méthode toggle doit simplement activer/désactiver l'attribut status selon l'état de la case à cocher :

toggle: function() {
var id = this.model.get('id')
, $el = this.$el.find('.check-task')
;

this.model.set('status', $el.attr('checked') ? 'completed' : 'needsAction');
if (this.model.get('status') === 'needsAction') {
this.model.set('completed', null);
}

this.model.save();
return false;
}

La nomenclature de Google pour l'état de la tâche propose completed et needsAction. Il faut un peu creuser dans la documentation pour le savoir.

VII - Résumé

Il a fallu un certain temps pour arriver aussi loin mais travailler avec des API inconnues avec leurs idiosyncrasies demande beaucoup de patience. Et si vous essayez d'exécuter le code de ce projet, assurez-vous que vous avez réellement des tâches et des listes dans Gmail. Cela ne fonctionne pas s'il n'y en n'a aucune. Je corrigerai ça plus tard !

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: Oh No Not More Tasks du site DailyJS.
Je remercie également _Max_ pour sa relecture attentive et assidue.