azz0r
azz0r

Reputation: 3311

BB Marionette: best way to update a collection without re-rendering

I have a very simple page that shows a collection in a table. Above it theres a search field where the user enters the first name of users.

When the user types I want to filter the list down.

Edit: I have updated the code to show how the current compositeView works. My aim is to integrate a searchView that can _.filter the collection and hopefully just update the collection table.

define([
  'marionette',
  'text!app/views/templates/user/list.html',
  'app/collections/users',
  'app/views/user/row'
],
  function (Marionette, Template, Users, User) {
    "use strict"

    return Backbone.Marionette.CompositeView.extend({
      template: Template,
      itemView: User,
      itemViewContainer: "tbody",
      initialize: function() {
        this.collection = new Users()
        this.collection.fetch()
      }
    })
  })

Upvotes: 0

Views: 1073

Answers (2)

Scott
Scott

Reputation: 469

You don't seem to be making use of CollectionView as well as you could be. If I were you I would separate the concerns between the search box and the search results. Have them as separate views so that when one needs to rerender, it doesn't effect the other.

This code probably won't work straight away as I haven't tested it. But hopefully it gives you some clue as to what ItemView, CollectionView, and Layout are and how they can help you remove some of that boiler plate code

//one of these will be rendered out for each search result.
var SearchResult = Backbone.Marionette.ItemView.extend({
    template: "#someTemplateRepresentingEachSearchResult"
)};

//This collectionview will render out a SearchResult for every model in it's collection
var SearchResultsView = Backbone.Marionette.CollectionView.extend{
    itemView: SearchResult
});

//This layout will set everything up
var SearchWindow = Backbone.Marionette.Layout.extend({
    template: "#someTemplateWithASearchBoxAndEmptyResultsRegionContainer",
    regions:{
        resultsRegion: "#resultsRegion"
    },
    initialize: function(){
        this.foundUsers = new Users();
        this.allUsers = new Users();
        this.allUsers.fetch({
            //snip...
        });
    events: {
        'keyup #search-users-entry': 'onSearchUsers'
    },
    onSearchUsers: function(e){
        var searchTerm = ($(e.currentTarget).val()).toLowerCase()

        var results = this.allUsers.filter(function(user){
            var firstName = user.attributes.firstname.toLowerCase();
            return firstName.match(new RegExp(searchTerm))
        });

        this.foundUsers.set(results); //the collectionview will update with the collection
    },
    onRender: function(){
        this.resultsRegion.show(new SearchResultsView({
            collection: this.foundUsers
        });
    }
});

I think the most important thing for you to take note of is how CollectionView leverages the Backbone.Collection that you provide it. CollectionView will render out an itemView (of the class/type you give it) for each model that is in it's collection. If the Collection changes then the CollectionView will also change. You will notice that in the method onSearchUsers all you need to do is update that collection (using set). The CollectionView will be listening to that collection and update itself accordingly

Upvotes: 0

Martin Lantzsch
Martin Lantzsch

Reputation: 1901

Divide your template in a few small templates, this increases performance at the client side, you don't have problems with overriden form elements and you have more reuseable code.

But be aware of too much separation, cause more templates means more views and more code/logic.

Upvotes: 2

Related Questions