map7
map7

Reputation: 5126

In backbone.js how do I bind a keyup to the document

I've been following along with a Railscast tutorial of backbone.js and I wanted to extend the functionality to include keyboard control. I added the following to my show view:

class Raffler.Views.EntryShow extends Backbone.View
  template: JST['entries/show']

  events:
    'click .back': 'showListing'
    'keyup': 'goBack'

  showListing: ->
    Backbone.history.navigate("/", trigger: true)

  goBack: (e) ->
    console.log e.type, e.keyCode

  render: ->
    $(@el).html(@template(entry: @model))
    this

On my show template I have the following:

<a href="#" class="back">Back</a>
<%= @entry.get('name') %></td>

If I select the back link using the tab key, then start hitting random keys I get output in my javascript console. However if I load the page and do not select the link and just start hitting keys I get no output in my console.

How do I bind the event to the document so that it will listen to any keys pressed when loading the screen?

Upvotes: 6

Views: 9247

Answers (2)

Linus Thiel
Linus Thiel

Reputation: 39251

Your events will be scoped to your view element @el. To capture events on the document, you have to roll that yourself:

initialize: ->
  $(document).on "keyup", @goBack

remove: ->
  $(document).off "keyup", @goBack

Should do the trick.

Upvotes: 4

Sander
Sander

Reputation: 13431

You will need to work around backbone's scope for views. when you are doing something like this:

  events:
    'click .back': 'showListing'
    'keyup': 'goBack'

you are binding your goBack function to the keyup event raised on your container element of your view. (by default the div in which the view is rendered)

instead of doing that, if you want to bind to something outside your view (which doesn't have it's own view!(*))

Raffler.Views.EntryShow = Backbone.View.extend({
  template: JST['entries/show'],

  events: {
    'click .back': 'showListing'
  },

  initialize: function () {
    $('body').keyup(this.goBack);
  },

  showListing: function () {
    Backbone.history.navigate("/", trigger: true);
  },

  goBack: function (e) {
    console.log e.type, e.keyCode;
  },

  render: function () {
    $(this.el).html(this.template(entry: @model));
    return this;
  }

});

(*)remark as marked above, you best do this only when the item you want to bind to does not have it's own view, if you have a view for your full page (an app view or something like that) you could bind the keyup in there, and just raise an event App.trigger('keypressed', e); for example.

you can then in your EntryShow view, bind to that App's keypressed event.

App.bind('keypressed', goBack);

keep in mind that you should do something as a delayed event or grouping keypresses together in some situations, as firing every keypress that happens in the body, might be a big performance hit. especially on older browsers.

Upvotes: 6

Related Questions