colorbox (which uses live) not rebinding after jQuery ajax call

13,440

Solution 1

The problem appears to be related to something I didn't notice at first and therefore didn't put in my question. I have edited the question to reflect this new information.

My issue was that AJAX response was multiple-binding and including the colorbox script multiple times. The Yii Framework helper widget I was using to include the script is also including jQuery and Colorbox in the response EACH TIME. Yii doesn't have a way to determine if the required scripts (like jQuery) have already been included in the main page (typical stateless HTTP issue) so it includes it in the AJAX partial render each time.

I solved this issue by not using a Yii Widget to do the Colorbox binding on each Ajax call's renderPartial view. I just include thecolorbox binding on the parent page, so the Ajax content has no JS in it.

Solution 2

First of all, you shouldn't use .live() it's deprecated. Instead learn how to use .delegate() You'll find this is a much more powerful listener and will help solve your problem.

On page load initially the DOM is ready, and colorbox is initilized for the selector AJAX calls a new piece of the page with some DOM element that is in the colorbox selector list, but isn't noticed because it loaded into the page after the selector was read by the javascript.

Try the following - as it watches body #main for all, existing and new a[rel='lightbox']:

$("body #main").delegate("a[rel='lightbox']", "click", function (event) {
                    event.preventDefault();
                    $.colorbox({href: $(this).attr("href"),
                            transition: "fade",
                            innerHeight: '515px',
                            innerWidth: '579px',
                            overlayClose: true,
                            iframe: true,
                            opacity: 0.3});});

EDIT for ".on()"

$("body #main").on("click", "a[rel='lightbox']", function (event) {
                        event.preventDefault();
                        $.colorbox({href: $(this).attr("href"),
                                transition: "fade",
                                innerHeight: '515px',
                                innerWidth: '579px',
                                overlayClose: true,
                                iframe: true,
                                opacity: 0.3
                         });
});

Yes, big change, I know, but the point is the 'on' method can also be used as 'bind', so that's kind of cool.

Solution 3

i solved this in a pretty easy way.

If you are sending back an ajax response (usually a javascript response) - attach the normal colorbox binding code (as you would do in any place) in that response.

$('.colorbox').colorbox({
  'iframe':true,
  'onClosed':function(){
    $("#featureList").load("/template/featureList","id="+$("#model_id").val());
  }
});

attach this in your js response from server. this worked for me.

Share:
13,440
thaddeusmt
Author by

thaddeusmt

I am a web developer and outdoor enthusiast. I mostly do HTML/CSS/JavaScript and PHP/MySql/MongoDB (on Apache/Nginx), but have dabbled in Java, .NET, Ruby, et al. I've done a lot of work with social APIs (Facebook, Twitter, Instagram), Drupal, WordPress, Magento, and the Yii framework, and also do server operations and administration. The phrase "full stack" comes to mind. I am currently the Chief Software Architect at http://splashlabsocial.com (built on Yii), where we build custom social media applications on top of our data platform.

Updated on July 09, 2022

Comments

  • thaddeusmt
    thaddeusmt almost 2 years

    I have a list of elements that I am loading via ajax (using jQuery's .load()). Each of these elements has an (edit) link next to it that lightboxes (using colorbox) a little edit form. When the lightbox is closed I use the onClosed callback to reload the ajax list to show and changes made during the edit.

    The colorbox call looks likes this:

    $('.colorbox').colorbox({
      'iframe':true,
      'onClosed':function(){
        $("#featureList").load("/template/featureList","id="+$("#model_id").val());
      }
    });
    

    My list looks like this:

    <div id="featureList">
      <ul id="features">
        <li id="item_000000000008+0">Element 1 (<a class="colorbox" href="/template/featureLightbox?template_id=000000000008&amp;delta=0">Edit</a>)</li>
        <li id="item_000000000008+1">Element 2 (<a class="colorbox" href="/template/featureLightbox?template_id=000000000008&amp;delta=1">Edit</a>)</li>
      </ul>
    </div>
    

    I looked at the colorbox source code and saw that is uses jquery live() to do the bind. Here it is:

    $('.' + boxElement).live('click', function (e) {
      if ((e.button !== 0 && typeof e.button !== 'undefined') || e.ctrlKey || e.shiftKey || e.altKey) {
        return true;
      } else {
        launch(this);   
        return false;
      }
    });
    

    You can see above the way colorbox works is by binding to "boxElement", which is a class it creates called "cboxElement". Before the live() bind colorbox adds this class (cboxElement) to all of the elements matching the selector (.colorbox in my example), then binds to this new class.

    So thought that if I placed the colorbox bind outside of the ajaxed content it would bind to the links after I replaced the #featureList div with ajax, since live() is supposed to bind to elements "now or in the future". But it doesn't because it's binding to .cboxElement instead of .colorbox so when the ajax reloads colorbox doesn't re-add the .cboxElement class to the elements.

    I tried calling $.fn.colorbox.init() in the ajax content to get colorbox to re-add the .cboxElement class to the elements, but this had no effect. (I do something like this when dealing with shadowbox, but it doesn't seem to work the same for colorbox.)

    So then I tried to place all the colorbox code inside the ajax content. When I do this the colorbox binds are stacking/chaining. So the second time I call it I get two colorboxes (and have to hit the "close" button twice to return to the main screen). The third time I get three. This is because when I call colorbox again it adds the .cboxElement class, making the old live() binds active again, and it also adds ANOTHER live() bind to it. I tried to clear out the .live() binds by calling .die() first, but it didn't work for some reason.

    I have found a couple of related posts but none of them solved this problem since colorbox is already using live():
    Problem with jQuery Colorbox
    jQuery AJAX table to a page but now the colorbox overlays no longer work

    Any other ideas out there? I am really stumped. I feel like I should switch to a different lightbox, but in general I like colorbox and it was working great everywhere else on the site until this ajax problem came up.

    Thanks!!!

    EDIT:

    So, in this case my issue was that my framework (Yii) was including a duplicate colorbox script on each AJAX call, which was causing the problem. So watch out for that!

    For everyone having issues who is NOT facing the duplicate-script issue I was: @Relic points out below you can sort of "sidestep" some issues by doing your own jQuery delegate() bind which does a "direct call" of colorbox, instead of relying on colorbox's default live() binding. I would tweak it like this for my case:

    $(document).delegate("#features a", "click", function (event) { // $.colorbox() call  }