0

I'm new at Backbone.js.And I hava some problem at this keyworks.I hava a Backbone view blow:

 var print = Backbone.View.extend({
    el : $('ul li.newItem'),  
    events : { 'click li.newItem':'printText'},
    initialize:function(){ 
      _.bind(printText,this);  // does 'this' refer to the li.newItem ?
      alert(1233); // init does't work.
    },
    printText : function(){
      //I wanna print the hello world text each list item when clicked.
    }
  });

 var print = new print();  

Here is my demo : http://jsbin.com/evoqef/3/edit

Ryan Yiada
  • 4,739
  • 4
  • 18
  • 20

2 Answers2

1

You have two problems that are keeping your initialize from working:

  1. There is no printText in scope.
  2. _.bind and _.bindAll behave differently.

The first is easy to fix, you want to use this.printText, not just printText.

_.bind binds a single function to a this and returns that bound function; _.bindAll, on the other hand, binds several named functions to a this and leaves the bound functions attached to the specified this. So, doing this:

_.bind(printText, this);

doesn't do anything useful as you're throwing away the bound function. You'd want to do this:

this.printText = _.bind(this.printText, this);

Or more commonly in Backbone apps, you'd use _.bindAll:

_.bindAll(this, 'printText');

Now you have a functioning initialize and you'll have the right this inside printText and we can move on to fixing printText. I think you want to extract the text from the <li> that was clicked; you can do this like this:

printText: function(ev) {
    console.log($(ev.target).text());
}

But that still doesn't work and we're left to wondering what's going on here. Well, Backbone binds events to a view's el so let us have a look at that:

var print = Backbone.View.extend({
    el : $('ul li.newItem'),
    //...

When that Backbone.View.extend runs, there won't be any li.newItem elements in the DOM so you won't get a useful el in that view. The usual approach here would be to have a view that looks like this:

var Print = Backbone.View.extend({
    tagName: 'li',
    events: {
        'click': 'printText'
    },
    render: function() {
        this.$el.text('Hello world ' + this.options.i);
        return this;
    },
    printText: function(e){
        console.log($(e.target).text());
    }
});

We set tagName to 'li' and let Backbone create the <li> by itself. Then we'd pass the counter value to the Print view as an argument, Backbone will take care of leaving the argument in this.options.i when we say new Print({ i: ... }).

Now we just have to adjust the addItem method in your ListView to create new Prints and add them to the <ul>:

addItem: function(){
    this.counter++;
    var v = new Print({ i: this.counter });
    this.$('ul').append(v.render().el);
}

Updated demo: http://jsbin.com/evoqef/10/edit

I've also made a few other changes:

  1. Use this.$el instead of $(this.el), there's no need to create something that's already available.
  2. Use this.$() instead of $('ul', this.el), same result but this.$() doesn't hide the context at the end of the $() function call and this.$() is more idiomatic in Backbone.
mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • Question. I've always wondered this. When you `this.printText = _.bind(this.printText, this);` it binds the function `printText()` to the view object. So `this` inside of `printText()` represents the View. I actually never use `_.bind()`, but use `this` inside my view functions all the time. They all seem to point to the View object correctly. What is the purpose of doing the `_.bind()` in such a manner if `this` already points correctly? – jmk2142 Sep 04 '12 at 06:35
  • 1
    @orangewarp: In general, `this` inside a function depends on how the function is called rather than how the function is defined. Consider the difference between `o.f()`, `f = o.f; f()`, and `f = o.f; f.call(x)`; all three are calling the same function but each one gives you a different `this` inside the function. There was some recent discussion of this over here: http://stackoverflow.com/q/12241696/479863 – mu is too short Sep 04 '12 at 06:50
0

In your _.bind(printText, this);

The printText is outside of the scope of the init function. this as your second argument represents the print Backbone.View.

You could do something like this:

_.bind(this.printText, this);

and probably rid yourself of the init() error. But you could use this inside of printText and it will represent your View anyway.

printText: function() {
    console.log(this);  // this represents your view
}
jmk2142
  • 8,581
  • 3
  • 31
  • 47