Позвоночник.js: удаление элемента из коллекции


Я использую позвоночник.js для реализации списка друзей ака реестр. Мой основной взгляд на коллекцию реестров и отдельных rosterEntry выглядит следующим образом:

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

Сейчас я тестирую с помощью консоли Firebug и могу заполнить список, выполнив следующее:

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

Добавление в коллекцию также работает нормально, выполнив следующее в консоли Firebug:

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

И новый rosterEntry добавляется в реестр.

Моя проблема в том, что это collection.remove(5) удаляет из коллекции в памяти, но ничего не делает для обновления DOM.

Как ни странно, если я удаляю функцию remove() из представления реестра, все записи в реестре удаляются. Если я добавляю этот метод, в котором нет ничего, кроме журнала консоли, то он вызывает метод remove как в списке, так и в представлениях RosterEntry - хотя я не знаю, почему, но они не в порядке!

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

Если я удаляю функцию remove из модели RosterEntry, я получаю следующее ошибка:

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

Что я делаю не так? Как удалить элемент из DOM, если он удален из коллекции?

3 5

3 ответа:

Я думаю, что у вас есть проблема с определением context в каждом событии привязки.

Попробуйте изменить это:

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

Для этого:

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

Я знаю, что вы пытались решить эту проблему с помощью bindAll, но bindAll обертывает каждый вызов перечисленных методов с контекстом фактического объекта, но это ничего не может сделать, если вы вызываете тот же метод на другом объекте :).

Обновлено

Я больше читаю.. похоже на bindAll и третий параматер команды bind делает то же самое. Так что, возможно, вы можете использовать одно или другое.

потому что не работает bindAll в model.remove потому что вы забыли добавить его в строку _.bindAll(this, 'render'), посмотрите в своем коде. И мое предложение исправило это, потому что, как я уже сказал, оба подхода делают то же самое.

Все это делается для того, чтобы гарантировать, что вызовы перечисленных методов (render, remove, ... в одном случае или this.remove в другом) будут интерпретировать this как ссылку на реальный объект. Это может выглядеть глупо, но this очень изменчиво в JS.

Не волнуйтесь, если вы все еще путаете с this вещью, я имею дело с ней уже давно и все еще не полностью cofindent.

Возможно это замечательный город такой может нам помочь.

Пробовали ли вы следующее?

this.listenTo(this.model, "remove", this.remove);
Это, кажется, работает на меня, и мне нравится, как это читается немного лучше.

Ссылка на Backbone doc

Методы remove в обоих представлениях, вероятно, вызываются, потому что вы обязаны удалить как модель, так и коллекцию.

В RosterEntry:

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

В Списке:

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