Backbone Collection - Filtering and rendering a collection loses the link to the original unfiltered collection

I am setting up an application running Backbone. I ran into the “should be simple” problem where I have a model called “Message”, a collection of “MessageList” and “Views” called “MessageView” and “MessageListView”.

MessageListView code displays a MessageList. I have 4 toggle buttons that filter what MessageListView shows. The filter buttons are All, Asset, Mark and Ignore. "All" is the initial page load filter. When the user clicks the Flag filter, only messages with the flag == 1 should appear. When the All button is clicked again, all messages should appear again.

The problem I am facing, and the problem in my design, is that when filtering a collection based on filterString, the link to the original whole collection is lost. So, when "All" is pressed again, the messages are lost.

I am wondering what is the best way to do this in Backbone ...

Here's the installation code ...

var messageListView = new MessageListView({collection: messageList}); 

Here's the code for MessageListView ...

 MessageListView = Backbone.View.extend({ initialize : function() { this.collection.on("add", function(model) { var view = new MessageView({model: model}); $("div.cameras").prepend(view.render().el); }); this.collection.on("remove", function(model) { var ID = model.id; $("#message-" + ID).parent("div.message").remove(); }); this.collection.on("reset", function(models) { $("div.cameras").empty(); models.each(function(message) { var view = new MessageView({model: message}); $("div.cameras").prepend(view.render().el); }); }); }, filterMessages : function(filterString) { var filtered = this.collection.filter(function(model){ if (filterString == "all") { return true; } else if (filterString == "active") { return model.get("ignore") == "0"; } else if (filterString == "ignore") { return model.get("ignore") == "1"; } else if (filterString == "flag") { return model.get("flag") == true; } }); this.collection.reset(filtered); }, 
+6
source share
2 answers

When you call

 this.collection.reset(filtered) 

You discard old data and replace it with new data.

Instead, you should have a temporary assembly (array or Backbone.Collection) to hold the filter results, and this is what you use as a “data source” to render your messages in the DOM.

There are several ways to do this.

  • Just visualize the output [array] of the filterMessages function in each case (including the "all" case), but do not return this result back to the original collection.
  • Create a second collection to get the results of the filterMessages function, and draw it again, leaving the original collection intact.
+10
source

You can use Backbone.CollectionView , which allows you to specify which models in the collection are currently visible using the visibleModelsFilter parameter.

Setup Code ...

 var messageListView = new MessageListView( { collection: messageList, modelView : MessageView } ); 

MessageListView Code ...

 MessageListView = Backbone.CollectionView.extend( { filterMessages : function(filterString) { if (filterString == "all") { this.setOption( "visibleModelsFilter", null ); } else if (filterString == "active") { this.setOption( "visibleModelsFilter", function( thisModel ) { return model.get("ignore") == "0"; } ); } else if (filterString == "ignore") { this.setOption( "visibleModelsFilter", function( thisModel ) { return model.get("ignore") == "1"; } ); } else if (filterString == "flag") { this.setOption( "visibleModelsFilter", function( thisModel ) { return model.get("flag") == true; } ); } } } ); 
+4
source

Source: https://habr.com/ru/post/913057/


All Articles