My current project involves a client application written using Backbone.js, and the FAQ page will appear in a lightbox. No big deal, right? Unfortunately, it’s not just as simple as it sounds because if you take a naive approach you find that you don’t get any event handling.

The lightbox I’m using in this example is fancyBox – very stable, very well written and very customisable. I highly recommend it!

Demo – to try these three approaches out for yourself, you can check the example app I wrote. You can also download the source code from here.

My first attempt, which seemed quite reasonable at the time, was this:

render: function() {
  this.$el.empty().append(this.template());

  var self = this;
  this.$el.fancybox({
    autoDimensions: true,
    autoCenter: true,
    afterClose: function() {
      self.close();
    }
  }
);
}

…and the result was…nothing. No lightbox appeared, and I didn’t even get an error reported in the log. Damn.

Try number two was more of an exploration to check that I can actually open a lightbox from within a Backbone view – it’s always worth confirming the basics when something doesn’t work as expected. With this code, the lightbox opens but no events are handled – you can click until you’re blue in the face, but nothing will happen.

render: function() {
  this.$el.empty().append(this.template());

  var self = this;
  $.fancybox(this.$el.html(),{
    autoDimensions: true,
    autoCenter: true,
    afterClose: function() {
      self.close();
    }
  });
}

Progress, at least. Finally, when examining the DOM elements created by fancyBox when the box is open, I found the key to a) a solution and, b), a filthy hack.

<div style="overflow: auto; width: 843px; height: auto;" class="fancybox-inner">

Bingo! I figured the easiest way to achieve success here was to cheat, and it works beautifully. The solution was an evolution of attempt #2, and has a couple of extra steps (highlighted in red below):

render: function() {
  this.$el.empty().append(this.template());

  var self = this;
  $.fancybox(this.$el.html(),{
    autoDimensions: true,
    autoCenter: true,
    afterClose: function() {
      $('#overlayArea').append(self.$el);
      self.close();
    }
  });

  $('.fancybox-inner').empty().append(this.$el);
}

1. The afterClose callback has been updated to re-append the el into the parent. This is done prior to the call to close(), to ensure things are in order.
2. The el is appended to the inner content holder of the lightbox. Because the entire el DOM is moved, all event handlers are still in place.

Note: The lightbox is still created using $.fancybox(this.$el.html()) in order to have it sized correctly.

It’s not the cleanest solution in the world, but if you have a need for opening lightboxes with Backbone components inside – this may come in handy.

2 thoughts on “Loading Backbone views into lightboxes

  1. Hey Steve,
    It seems like your solution is not working with Safari, have you tried it there? In chrome everything looks good

    1. Hey Andreas,

      It’s been tested in Chrome and Firefox on Linux, Firefox and IE 9 on Windows and whatever the default browser in ICS is. I’ll see if I can get Safari installed in Ubuntu and test further there.

      Thanks for the feedback!

Leave a Reply

Your email address will not be published. Required fields are marked *