-1

I am trying to filter a collection based on an attribute called status. Once filtered I want to re-render the view to reflect the filtered results. So far I have come up with this function in my collection.

var ProjectCollection = Backbone.Collection.extend({

    url: '/projects',
    model: app.Project,

    status: function( status ) {
        return this.filter(function(project){
            return project.get('status') == status;
        });
    },
});

In my view I the run the following,

filterStatus: function(e) {
    e.preventDefault();

    var elm = $(e.currentTarget),
        status = elm.data('statusid');


    this.collection.reset( this.collection.status( status ) );

}

The render function is below along with it's functions that also get called,

render: function() {
    this.$el.empty();

    console.log("ProjectDashboardView render");

    if(this.collection.length < 1) {
        var noProjects = new app.noProjectsDashboard;
    } else {

        this.addAll();
    }

    $(".month-column").height($(".project-holder").height() + 50);
},

addAll: function() {
    console.log("allAdd");
    this.collection.each(function(model){
        this.addOne(model)
    }, this);
},

addOne: function(model) {
    var view = new app.ProjectTimelineEntry({ 
        model: model 
    });

    this.$el.append( view.render() );

    var number_of_days_in_calendar = 0;

    $('.month-column').each(function(){
        number_of_days_in_calendar = number_of_days_in_calendar + parseInt($(this).data('days'));
    });

    var day_width = 1/(number_of_days_in_calendar) * 100;


    //Is the start after the end of Feb?
    var start_date = new Date(model.get('start_date'));
    var march_date = new Date("03/01/2014");

    var current_month = start_date.getMonth() + 1;
    var march_month = march_date.getMonth() + 1;
    console.log(current_month, march_month);
    if(current_month <= march_month) {
        var start_date_offset = model.get('num_days_from_year_start') * day_width;
        var duration_of_project = model.get('run_number_days') * day_width;
        //view.$('.duration-bar').css("background-color", model.get('color'));
        view.$el.find('.duration-bar').css({
            width : duration_of_project + "%",
            "margin-left" : start_date_offset + "%"
        }, 500);
    } else {
        var start_date_offset = (model.get('num_days_from_year_start') + 2) * day_width;
        var duration_of_project = model.get('run_number_days') * day_width;
        //view.$('.duration-bar').css("background-color", model.get('color'));
        view.$el.find('.duration-bar').css({
            width : duration_of_project + "%",
            "margin-left" : start_date_offset + "%"
        }, 500);
    }

    // if(Date.parse(start_date) < new Date("01/03")) {
    //  console.log("before march");
    // }


},

Now this filters the collection, however what happens is that when I try and filter the collection again, it filters the collection that I have just reset too, how can I filter the collection, run the views render() function once a filter is complete, but not keep resetting the collection?

Udders
  • 6,914
  • 24
  • 102
  • 194

2 Answers2

1

As hindmost mentionned, you should add a visible field to app.Project model. Then in ProjectView attach a listener to this field:

this.listenTo(this.model, "change:visible", this.onVisibleChange)

and the method definition:

onVisibleChange: function(){
    $(this.el).css('display', (this.get('visible')) ? 'block': 'none')
}

In your filter method you run over the collection and change the visible field of each model accordingly to if it should or should not being rendered.

var ProjectCollection = Backbone.Collection.extend({

    url: '/projects',
    model: app.Project,

    status: function( status ) {
        return this.each(function(project){
            project.set('visible',  project.get('status') == status)
        });
    },
});
Mironor
  • 1,157
  • 10
  • 25
0

You have to add extra attribute to collection's model (app.Project) which will store the flag indicating if a project has to be displayed or not.

var app.Project = Backbone.Model.extend({
    defaults: {
        ...
        status: '',
        display: true
    }
};

Then you have to add the code to model View's render which will show/hide View's element depending on value of display attribute:

var ProjectView = Backbone.View.extend({
    ...
    render: function() {
        ...
        if (this.model.get('display'))
            this.$el.show();
        else
            this.$el.hide();
        ...
        return this;
    },
    ...
};

And, finally you have to modify ProjectCollection's status method to set display attribute on each model:

var ProjectCollection = Backbone.Collection.extend({
    url: '/projects',
    model: app.Project,

    status: function( status ) {
        this.each(function(project){
            project.set('display', project.get('status') == status);
        });
    },
    ...
});
hindmost
  • 7,125
  • 3
  • 27
  • 39