39 votes

Backbone.js - Méthode correcte de filtrage et d'affichage des données de collection dans une vue

J'ai une énorme liste de tâches chargé sur le départ.
Je veux leur montrer en fonction de la liste sélectionnée / boîte de réception, de sorte qu'il n'existe pas de charges supplémentaires pour chaque liste.

window.Task = Backbone.Model.extend({});

window.TasksCollection = Backbone.Collection.extend({
    model: Task,
    url: '/api/tasks',
    inbox: function() {
        return this.filter(function(task) {
            return task.get('list') == null;
        });
    },
    list: function(id) {
        return this.filter(function(task) {
            return task.get('list') == id;
        });
    }
});

window.tasks = new TasksCollection;

window.TaskView = Backbone.View.extend({
    tagName: 'li',
    template: _.template($('#item-template').html()),
    initialize: function() {
        _.bindAll(this, 'render', 'close');
        this.model.bind('change', this.render);
        this.model.view = this;
    },
    render: function() {
        $(this.el).html(this.template(this.model.toJSON()));
        this.setContent();
        return this;
    },
});

window.TasksView = Backbone.View.extend({
    el: '#todo-list',
    collection: tasks,
    initialize: function() {
        _.bindAll(this, 'render');
        this.collection.bind('reset', this.render);
        this.collection.fetch();
    },
    render: function() {
        var t = this;
        $(t.el).html('');
        this.collection.each(function(task) {
            var view = new TaskView({ model:task });
            $(t.el).append( view.render().el );
        });
        return this;
    },
});

window.Nicetask = Backbone.Router.extend({
    routes: {
        '':             'inbox',
        '/inbox':       'inbox',
        '/list/:id':    'list',
    },
    initialize: function() {
        _.bindAll(this, 'inbox', 'list');
        window.tasksView = new TasksView;
    },
    inbox: function() {
        tasks.reset( tasks.inbox() );
    },
    list: function(id) {
        tasks.reset( tasks.list(id) );
    }
});

Ce code fonctionne, mais l' reset() fonction supprime d'autres tâches dans la liste de tâches de collecte. Et sur une autre route, les tâches de la collection est vide.

Est-il raisonnable de la façon d'atteindre cet objectif? merci pour toute idée.

ps: épine dorsale débutant


Mise à JOUR

Merci à @traîneau et @ibjhb pour les commentaires, ici est extrait de la solution de travail.

window.TasksView = Backbone.View.extend({
    el: '#todo-list',
    collection: Backbone.Collection.extend(),
    initialize: function() {
        _.bindAll(this, 'render', 'addOne', 'addAll');
        this.collection.bind('add', this.addOne);
        this.collection.bind('reset', this.render);
    },
    render: function(data) {
        $(this.el).html('');
        _.each(data, function(task) {
            this.addOne(task);
        }, this);
        return this;
    },
    addOne: function(task) {
        var view = new TaskView({ model:task });
        $(this.el).append( view.render().el );
    },
});

window.Nicetask = Backbone.Router.extend({
    routes: {
        '':             'inbox',
        '/inbox':       'inbox',
        '/today':       'today',
        '/list/:id':    'list',
    },
    initialize: function() {
        _.bindAll(this, 'inbox', 'today');
        window.tasksView = new TasksView;
        window.menuView = new MenuListView;
        tasks.fetch();
    },
    inbox: function() {
        tasksView.render( tasks.inbox() );
    },
    today: function() {
        tasksView.render( tasks.today() );
    },
    list: function(id) {
        tasksView.render( tasks.list(id) );
    }
});

13voto

sled Points 8468

Peut-être que c'est exagéré, mais j'ai dû écrire une Dorsale sous-ensemble de la classe n'y a pas longtemps; vous pouvez l'utiliser si vous le souhaitez:

Le truc c'est que j'ai une grande collection de tenue de tous les modèles. Le sous-ensembles juste de filtrer les modèles qui satisfont à la condition de filtre, mais ils se comportent comme un normal épine dorsale de la collection :)

4voto

James Brown Points 364

Je pense que vous devez utiliser une autre collection. Par exemple, dans votre boîte de réception, procédez comme suit:

 inbox: function(){
    currentCollection = new TasksCollection(tasks.inbox());
}
 

Je n'ai pas testé cela, mais quand vous faites un .reset (); vous supprimez tous vos modèles et chargez ceux qui ont été transmis.

4voto

bazzargh Points 1293

@sled il y a des fautes de frappe dans le code que vous avez posté, voir les commentaires en ligne. Avez-vous posté ceci en tant que projet quelque part?

 // add models
add: function(models, options) {
  // TYPO: next line was missing, so single models not handled.
  models = _.isArray(models) ? models.slice() : [models];

  var self = this;

  models = _.filter(models, this.filter);

  // return if no models exist
  // TYPO: returned undefined, so was not chainable
  if(models.length == 0) { return this; }

  // actually add the models to the superset
  this.superset.add(models, options);
  return this;
},

// remove models
remove: function(models, options) {
  // TYPO: next line was missing, so single models not handled.
  models = _.isArray(models) ? models.slice() : [models];

  // remove model from superset
  this.superset.remove(_.filter(_.filter(models, function(cm) {
    // TYPO: not 'm != null', causes error to be thrown
    return cm != null;
  }), this.filter), options);
  // TYPO: missing return so not chainable
  return this;
},
 

1voto

andy t Points 1026

une petite modification pour vous la solution, que vous utilisez

$(this.el).html('');

Ma compréhension est votre les points de vue et des événements liés à des liaisons existent encore dans le navigateur de mémoire, donc, idéalement, vous devez utiliser la vue.remove() sur le TaskView correctement effacer les liaisons d'événements ainsi que le code html.


C'est un peu différente sur la réponse que j'ai été à la recherche d'une solution à un problème similaire, espérons que ce peut être de l'aide aux autres.

Mon problème: - pour filtrer une collection complète par des attributs du modèle. par exemple. un utilisateur clique sur les modèles de vue, permet d'obtenir une liste de (certains de) ces attributs, la sélection d'un attribut filtres de la collection d'afficher uniquement avec la même valeur.

La route que je prends est par l'appel d'une méthode sur le recouvrement de la vue, dans mon cas, la vue est spécifique à un modèle de sorte que:

this.model.collection.myFilter(attr,val);

lorsque l'attribut est un attribut du modèle associé avec la collection, puis dans le filtre à quelque chose comme

myFilter: function(attr, val){
    var groupByAttr = this.groupBy(function(article){
        var res = (val === undefined)? true : (article.get(attr) == val);
        article.set({selected:res});
        return res;
    });
    return groupByAttr;
}

J'ai utilisé ._groupBy , car cela renvoie 2 tableaux (positif / négatif) que l'on peut utiliser. En réglant le mode de l'attribut "selected", et la liaison à présent dans la vue modèle, je peux facilement faire basculer une classe qui affiche ou masque la vue.

if(val === undefined) est ajouté comme un simple moyen de nettoyer un filtre par un appel à la même méthode sans valeur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X