4

I have a View in Backbone that contains an inner div. I want to hide the div when the user clicks outside of the div.

I'm not sure how to set up an Event inside of the View that says "click NOT #inner_div": "removeDiv".

Any suggestions on how to do this?

egidra
  • 8,537
  • 19
  • 62
  • 89

3 Answers3

3

The usual approach is to attach a click handler directly to <body> and then have that close or hide your <div>. For example:

render: function() {
    $('body').on('click', this.remove);
    this.$el.html('<div id="d"></div>');
    return this;
},
remove: function() {
    $('body').off('click', this.remove);
    // This is what the default `remove` does.
    this.$el.remove();
    return this;
}

If you just want to hide the <div> rather than remove it, just bind clicks on <body> to a different method than remove; you'll still want to remove the click handler from <body> in your remove though. Also, you'll want to trap click events on your view's el to keep them from getting to <body>.

Demo: http://jsfiddle.net/ambiguous/R698h/

If you have other elements that care about click events then you could absolutely position a <div> to cover up the <body> and then bind your click handler to that. You could have a look at the jQuery BlockUI plugin to see how this is done.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
0

If you use Prototype, you can do this:

initialize: function() {
  // some code
  document.on('click', function(e, target) {
    if (target !== this.el && target.up('#inner_div').length === 0) {
      this.remove();
    }
  }.bind(this));
}

I guess with jQuery it might look like this:

initialize: function() {
  // some code
  $(document).on('click', function(e) {
    if (e.target !== this.el && e.target.parent('#inner_div').length === 0) {
      this.remove();
    }
  }.bind(this));
}
mvbl fst
  • 5,213
  • 8
  • 42
  • 59
0

Although manipulating the DOM directly works you could let Backbone handle things for you by giving your views some appropriate structure. For instance:

BoxView = Backbone.View.extend({
  events: {
    'click': '_click'
  },

  _click: function() {
    return false;
  }
});

AppView = Backbone.View.extend({
  el: '.app',

  initialize: function() {
    this.boxView = new BoxView({ el: $('.box') })
  },

  events: {
    'click': '_click'
  },

  _click: function() {
    this.boxView.remove();
  }
});

new AppView({ el: $('.app') });

This way we can change the inner view once clicks on outer view are triggered. Note the binding on BoxView click event to prevent it from being disposed when user clicks on it.

Demo: https://jsfiddle.net/embs/45da2ppm/

In case you already have a complex structure of Backbone views that cannot be easily refactored into subviews structure, you may still make use of Backbone.Events module to listen to outer views' click events within the inner view and then manipulate it as you wish.

I'd also recommend checking out this nice article regarding common mistakes when working with Backbone. Some of them are closely related to your question:

Matheus Santana
  • 581
  • 1
  • 6
  • 22