简体   繁体   中英

Why are all item being removed from my Backbone.js view when I click the X

js. I would like to know why my backbone.js is removing both items when I click on the X next to the album and artist.

ie

The Chronic-- Dr. Dre-- X
Ten-- Pearl Jam-- X

I appreciate any feedback that I could get that would allow me to only remove one item as opposed to both

Javacript:

(function($){

Backbone.sync = function(method, model, success, error){ 
    success();
}

//Declare model 
var Album = Backbone.Model.extend({
defaults: {
    album: 'Logical Progresions vol. 1',
    artist:'LTJ Bukem'
    }
});

//Declare collection
var eList = Backbone.Collection.extend({
    model: Album
});


//Declare the view for the Albums
var AlbumView = Backbone.View.extend({
    el: $('div#main'),
    template: _.template(
            "<div class=\"alert\"> " +  
            "   <span class=\"album\"><%= album %>--</span> " +
            "   <span claas=\"artist\"><%= artist %>--</span> " +
            "   <span class =\"delete\">X</span> " +
            "</div>"
            ),


    events: { 
        'click span.delete':  'deleteAlbum'
    },  

    initialize: function(){
        _.bindAll(this, 'render','unrender','deleteAlbum');
        this.model.bind('remove', this.unrender);
    },

    // `unrender()`: Makes Model remove itself from the DOM.
    unrender: function(){
        this.$el.remove();
    },


    deleteAlbum: function(){
        this.model.destroy();
    },

    render: function(){
        $(this.el).append(this.template(this.model.toJSON()));
    }
});


var appendItem = function(item){
    var albumView = new AlbumView({
        model: item
        });
     albumView.render();
}

//// set the stuff in motion
var elist = new eList();

elist.bind("add",function(listItem){appendItem(listItem)});


elist.add({
    album: 'The Chronic',
    artist: 'Dr. Dre'
    });

elist.add({
    album: 'Ten',
    artist: 'Pearl Jam'
    });

})(jQuery);

There are a few things I can point out.

First, your view - when you create multiple instances for each album - each share the same el. That is, div#main. Each time you add one, you're appending the template stuff to the el which is why you still see the other. But when you click on .delete and execute the this.$el.remove() you are removing everything in the el. Which includes the other view.

You should separate it out, each view should have it's own unique el.

el: 'div',
className: 'albumView'

When you add each album view, you can create the view and append it to your div#main

var view = new AlbumView();
$('#main').append(view.render().el);  // the el refers to the subview (albumView) el.

This should keep each view happy with its own el and removal will only affect that view/model/DOMelement.

UPDATE - context of $('#main').append(view.render().el);

Basically, when you create the albumViews and append them the most ideal place to do this is in the larger context in which your div#main exists. For example, this might happen in your main js script in the header, or maybe even in a larger view that contains many albumView subviews. To illustrate the subview context:

var ParentView = Backbone.View.extend({
    el: $('#main'),
    render: function() {
        this.addAllAlbums();  // On rendering the parent view, we add each album subview
        return this;
    },
    addAllAlbums: function() {
        var self = this;

        // This loops through the collection and makes a view for each album model
        this.collection.each(function(albumModel) {
            self.addAlbumView(albumModel);
        });
    },
    addAlbumView: function(albumModel) {
        var view = new AlbumView({
            'model': albumModel
        });

        // We are adding/appending each albumView to this view's el
        this.$el.append(view.render().el);

        // ABOVE: `this.$el` refers to ParentView el. view.render().el refers to the
        // albumView or subview el.

        // As explained before, now each album view has it's own el which exists in
        // the parent view's this.el = `$('#main')`
    }
});


// We create the parent BIG/ALLAlbumsView and toss into it the collection of albums
var BigAlbumsView = new ParentView({
    'collection': albumsCollection
});

BigAlbumsView.render();  // Run the `render()` to generate all your album subviews

You might also want to store reference to those subviews by adding these lines in your code of the parent view. It will make cleaning up easier although it's not a big deal if you intend on cleaning up individual views through the subviews themselves.

// In your initialization, we create an array to store album subviews
this.albumViews = [];

// In `addAlbumView()` we push each view into the array so we have a reference
this.albumViews.push(view);

// When cleaning up, you just simply cycle through the subviews[] and remove/close
// each album subview
_.each(this.albumViews, function(albumView) {
    albumView.$el.remove();
});

Hope this helps.

PS - Last note that I noticed. When you remove a view, I noticed you use remove() which is the way to get it out of the DOM. If you're making more complex subviews intertwined/tangled with event listeners to collections, models, and other views - you might want to read Derick Bailey's take on Zombie views and implementing a close() method that will both remove() and unbind() your view so there are no references to it and it can be garbage collected. Not the focus of this question but good for extra credit and possibly relevant since this has probably made your code more complicated. :-P

Removing Views - avoiding zombies

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM