Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone.js : Remove an item from a collection

I'm using backbone.js to implement a buddy list aka Roster. My backbone view for the Roster collection and individual rosterEntry are as follows:

    Slx.Roster.Views.RosterEntry = Backbone.View.extend({
    tagName: "li",
    className : "rosterEntry clearfix",
    templateSelector: '#rosterEntryTemplate',

    initialize: function() {
        _.bindAll(this, 'render');
        this.model.bind('change', this.render);
        this.model.bind('remove', this.remove);
        this.template = _.template($("#rosterEntryTemplate").html());
    },

    remove: function () {
        debug.log("Called remove event on model");
        $(this.el).remove();
    },
    render: function() {
        var renderedContent = this.template(this.model.toJSON());
        this.id = this.model.Id;
        $(this.el).attr('id', "friendid-" + this.model.get("id")).html(renderedContent);
        return this;
    }
});

    Slx.Roster.Views.Roster = Backbone.View.extend({
        el: "div#roster-container",
        initialize: function () {
            _.bindAll(this, 'render', 'add', 'remove');
            this.template = _.template($("#rosterTemplate").html());
            this.collection.bind('reset', this.render);
            this.collection.bind('add', this.add);
            this.collection.bind('remove', this.remove);
        },
        add: function (rosterEntry) {
            var view = new Slx.Roster.Views.RosterEntry(
                {
                    model: rosterEntry
                });
            $(this.el).append(view.render().el);
        },
        remove: function (model) {  // if I ommit this then the whole collection is removed!!
            debug.log("called remomve on collection");
        },
        render: function () {
            var $rosterEntries, collection = this.collection;

            $(this.el).html(this.template({}));
            $rosterEntries = this.$('#friend-list');

            _.each(collection.models, function (model) {
                var rosterEntryView = new Slx.Roster.Views.RosterEntry({
                    model: model,
                    collection: collection
                });

                $(this.el).find("ul#friend-list").append(rosterEntryView.render().el);
            }, this);

            return this;
        }
    })

I'm testing for now using the Firebug console and can populate the roster just fine by executing the following:

collection = new Slx.Roster.Collection
view = new Slx.Roster.Views.Roster({collection:collection})
collection.fetch()

Adding to a collection also works fine, by executing the following in the Firebug console:

collection.add(new Slx.Roster.Model({username:"mickeymouse"})

and the new rosterEntry is added to the Roster.

My problem is that collection.remove(5) removes from the in-memory collection, but does nothing to update the DOM.

Strangely, if I ommit the remove() function from the Roster View, all the entries in the roster are removed. If I add this method with nothing in it but a console log, it the remove method on both the Roster and RosterEntry views is called - although I'm not sure why but they are out of order!

["Called remove event on model"]
["called remomve on collection"]

if I delete the remove function from the RosterEntry model I get this error:

TypeError: this.$el is undefined
this.$el.remove();

What am I doing wrong? How do I remove the element from the DOM when it is removed from the collection?

like image 868
reach4thelasers Avatar asked Nov 13 '22 07:11

reach4thelasers


1 Answers

I think you have a problem with the context in every event bind definition.

Try to change this:

this.model.bind('remove', this.remove);

For this:

this.model.bind('remove', this.remove, this);

I know you have tried to solve this with the bindAll, but bindAll is wrapping every call to the listed methods with the context of the actual object, but this can't do anything if you are calling the same method on other object :).

Updated

I have reading more.. looks like bindAll and the third paramater of the bind command do exactly the same. So maybe you can use the one or the other.

The because is not working the bindAll in the model.remove is because you forgot to add it to the _.bindAll(this, 'render') line, look in your code. And my suggestion fixed it because as I say both approachs do the same.

What all this is doing is assuring that the calls to the listed methods (render, remove, ... in one case or this.remove in the other) are gonna interpretate this as a reference to the actual object. This can look stupid but this is very volatile in JS.

Don't worry if you are still confused with the this thing, I have dealing with it for long and still not completely cofindent.

Maybe essais like this can help us.

like image 70
fguillen Avatar answered Nov 16 '22 03:11

fguillen