2011-07-28 7 views
39

Tengo una enorme lista de tareas cargadas desde el principio.
Quiero mostrarlos dependiendo de la lista/buzón de entrada seleccionada, para que no haya cargas adicionales para cada lista.Backbone.js - Forma correcta de filtrar y mostrar los datos de la colección en una vista

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)); 
    } 
}); 

Este código funciona, pero la función reset() elimina otras tareas en la lista real de la colección de tareas. Y en otra ruta, la recolección de tareas está vacía.

¿Hay alguna manera razonable de lograr esto? gracias por cualquier idea

ps: columna vertebral novato


ACTUALIZACIÓN

Thx a @sled y @ibjhb para comentarios, aquí es fragmento de la solución de trabajo.

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)); 
    } 
}); 
+2

estado saliendo de mi cabello durante horas. ¡gracias por la respuesta! – Chev

+1

¿Usando Backbone Marionette tal vez? Eso resuelve muchos problemas. – Blacksonic

+0

Hola Juraj, tengo una situación en la que obtengo un json tree y tengo que crear una colección solo cuando hacemos clic en los nodos secundarios. Por ej. Root1> child1> subchild1. Aquí tengo que mostrar primero los nodos raíz y solo al hacer clic en el nodo raíz 'Root1', se debe mostrar la lista secundaria 'child1' o se debe crear la colección secundaria. Acabo de encontrar tu situación algo similar. ¿Puedes arrojar algo de luz sobre esto? Gracias de antemano –

Respuesta

4

Creo que necesita usar otra colección. Por ejemplo, en la bandeja de entrada, haga lo siguiente:

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

No he probado esto, pero cuando se hace una .reset(); va a extraer todos sus modelos y la carga de las aprobadas en.

1

una modificación rápida para la solución, que está utilizando

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

Mi entendimiento es tu los puntos de vista y enlaces de eventos relacionados seguirán existiendo en el navegador memoria, por lo que idealmente necesita usar view.remove() en el TaskView para borrar correctamente los enlaces de evento así como también el html.


Esta es una visión ligeramente diferente en la respuesta como lo he estado buscando una solución a un problema similar, espero que esto puede ser de ayuda para otras personas.

Mi problema: - filtrar una colección completa por atributos del modelo. p.ej. un usuario hace clic en la vista de modelos, obtiene una lista de (algunos de) los atributos, selecciona un atributo filtra la colección para mostrar solo los que tienen el mismo valor.

La ruta que estoy tomando es llamando a un método en la colección de la vista, en mi caso, la vista es específico para un modelo tan:

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

donde attr es un atributo del modelo asociado la recogida, a continuación, en el filtro de algo como

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; 
} 

he utilizado ._groupBy como esto devuelve 2 arrays (positivo/negativo) que puede ser de uso. Al configurar el atributo de modo "seleccionado" y vincular esto en la vista de modelo, puedo alternar fácilmente una clase que muestra u oculta la vista.

if (val === undefined) se agrega como una forma simple de borrar un filtro llamando al mismo método sin un valor.

+0

Interesante. ¿Cómo 'JSONify' el resultado para las plantillas? – charlysisto

4

@sled hay errores ortográficos en el código que ha publicado, vea los comentarios en línea. ¿Publicaste esto como un proyecto en alguna parte?

// 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; 
}, 
Cuestiones relacionadas