0

Iam developing a simple application to add and remove names from a ul. I have a input and a button , when i click button , text in input is appended to ul.My code is :

<input type="text" placeholder="Enter friend's name" id="input" />
<button id="add-input">Add Friend</button>

<ul id="friends-list">
</ul>

Backbone Code :

<script>
    $(function() {

        FriendList = Backbone.Collection.extend({
            initialize: function(){

                this.bind("add", function( model,options ){
                    var id = ( model.collection.indexOf(model) );
                    view.render(model,id);
                });
                this.bind("remove",function(model){
                    alert("here");
                });

            }
        });

        FriendView = Backbone.View.extend({

            tagName: 'li',

            events: {
                'click #add-input':  'getFriend',
                'click .button': 'removeFriend'
            },

            initialize: function() {
                this.friendslist = new FriendList;
                _.bindAll(this, 'render');
            },

            getFriend: function() {
                var friend_name = $('#input').val();
                this.friendslist.add( {name: friend_name} );

            },

            removeFriend: function(){
                var friend_index = $('.button').attr('id');
                alert(friend_index);

                this.friendslist.remove();
            },

            render: function( model,id ) {
                $("#friends-list").append("<li>"+ model.get("name")+"<button class=button id="+id+">"+"delete"+"</button>"+"</li>");

                $('#input').val('');

            }

        });

        var view = new FriendView({el: 'body'});
    });
</script>

My problems , where iam stuck :

i) Add functionality is running just fine , when i click delete button , it goes to removeFriend function but does not goto the collection and alert ("here"); ii) Please Help me write code for deleting/removing an li on clicking delete button

Thank you

Nishant Jani
  • 1,965
  • 8
  • 30
  • 41

1 Answers1

2

Getting started with Backbone is confusing. I started with the assumption that it could do more than it can by default. Instead, it is a building block to build upon (see backbone marionette and similar projects). I've refactored your code a bit with these things in mind:

  1. FriendView has too much knowledge: it shouldn't have to know where to insert itself into the DOM.
  2. Some assumptions are made about how Backbone works with rendering collections. Backbone doesn't implement collection rendering so it is left up to you. The easiest way is render each item in the collection and append them to the DOM. So when an item is removed, the entire collection is rendered again. Sounds bad, right? In practice it may not matter. You can implement more complex rendering approaches but my advice is to start with the basics and work from there.
  3. The DOM should reflect the state of Backbone (collections, models) -- you should avoid manipulating the DOM directly as much as possible and allow Backbone state changes/events to direct updating the DOM. You can see this in how removing a friend is done: remove the friend from the collection which triggers a remove event on the collection which is bound to rendering the FriendListView.

So how to fix your code? This is what I did: http://jsfiddle.net/Gd2Rs/

$(function() {

    FriendList = Backbone.Collection.extend();

    FriendListView = Backbone.View.extend({
        initialize: function(e, c) {
            this.collection.bind('add', this.render, this);
            this.collection.bind('remove', this.render, this);
        },

        events: {
            'click #add-input':  'addFriend'
        },

        addFriend: function() {
            var friend_name = $('#input').val();
            $('#input').val('');
            this.collection.add({name: friend_name});
        },

        render: function() {
            var list = this.el.find('#friends-list');
            list.empty();
            this.collection.each(function(model) {
                var friendView = new FriendView({model: model});
                list.append(friendView.render().el);
            });
        }
    });

    FriendView = Backbone.View.extend({

        tagName: 'li',

        events: {
            'click .button': 'removeFriend'
        },

        removeFriend: function(){
            this.model.collection.remove(this.model);
        },

        render: function() {
            $(this.el).html(this.model.get('name') + "<button class='button'>"+"delete"+"</button>");
            return this;
        }
    });

    var view = new FriendListView({
        el: $('#friends'),
        collection: new FriendList()
    });
});​

Note that I've intentionally avoided optimizing FriendListView.render because I think it's the wrong way to go with Backbone. You're going to either need to build your own collection rendering which you should reuse or use something like backbone marionette. The boiler plate code using Backbone directly gets tiresome.

Cymen
  • 14,079
  • 4
  • 52
  • 72
  • you solution is soo perfect thank you so much can u help me out with some little other stuffs (v basic) in the chat maybe ? thank you for the solution none-the-less , v v thankful – Nishant Jani Nov 22 '12 at 09:02
  • can u elaborate on this line please @cymen ? var friendView = new FriendView({model: model}); – Nishant Jani Nov 22 '12 at 09:44
  • i am getting an error saying : Uncaught TypeError: Cannot call method 'find' of undefined and Uncaught TypeError: Cannot call method 'each' of undefined in the render function of FriendListView , can you please help out @cymen – Nishant Jani Nov 22 '12 at 11:02
  • Are you getting that on the jsfiddle? If so, what browser and version are you using? – Cymen Nov 23 '12 at 03:44
  • The line `var friendView = new FriendView({model: model})` is creating a friend view for the model which comes from iterating over the collection of models. So we iterate the collection with `each` and the function is `function(model) { ... }` so model comes from collection. Does it make sense? – Cymen Nov 23 '12 at 03:46
  • yes , thank you sooo much , one last last thing , can you help out with list.append(friendView.render().el); i really got tossed away by the parameter youv passed to append function, thanks alot @cymen :) – Nishant Jani Nov 23 '12 at 06:11
  • So we have an instance of a view named `friendView` and we tell it to render itself. But we want the HTML that rendering it creates because we want to put it in a specific place. So we can get this HTML by access the `el` attribute on what is returned by `render()`. You can try all of this in Chrome -- simply put `debugger;` after that line and open the developer tools. Then you can access the `friendView` variable in the console and play with it to see what happens with `render()` and when you access `el`. – Cymen Nov 23 '12 at 06:14
  • i know this is well beyond the scope of my question and i feel guilty too but can u please educate me on the chrome part you just mentioned , youv been really helpful , thanks @cymen , i cant get exact what u said about developer tools in chrome – Nishant Jani Nov 23 '12 at 07:44
  • 1
    You should google for more information -- there are some Youtube videos that are helpful like thes: http://www.youtube.com/watch?v=7cqh7MGLgaM and http://www.youtube.com/watch?v=c_oiQYirKuY – Cymen Nov 23 '12 at 15:23
  • thank you soo soo much @cymen , uv been v helpful indeed :D :) – Nishant Jani Nov 24 '12 at 07:59
  • can u tell me one small doubt i have ? we make an instance of FriendListView and pass colleciton to it , then in the render function of FriendListView we make an instance of FriendView and pass just the model, then in the render of FriendView how can we access the collection ? – Nishant Jani Nov 24 '12 at 19:38
  • The render of FriendView shouldn't know anything about being part of a collection. It shouldn't need to and it doesn't as it's primary concern is rending one single friend and handling any events for that rendered friend. – Cymen Nov 25 '12 at 01:54
  • iam sorry but i guess you have got me wrong , my doubt is , we have done this *var view = new FriendListView({ el: $('#friends'), collection: new FriendList() });* so collection is available in the FriendListView , then how are we able to access collection in the FriendView when we do this *this.model.collection.remove(this.model);* how is collection accessible here @cymen – Nishant Jani Nov 25 '12 at 07:24
  • Normally, I would consider triggering an alert for the remove to have `FriendListView` handle it. Take a look at my answer on this thread for an example: http://stackoverflow.com/questions/10147969/saving-jquery-ui-sortables-order-to-backbone-js-collection/10149738#10149738 – Cymen Nov 25 '12 at 17:22