Jquery – Ajax Link inside ajax loaded content problem

Problem

We know how to load a content via ajax very easily using jquery with $.ajax{} or load(). But there is a problem of handling the events inside that dynamically loaded content.

Solutions

Consider we are loading some content using ajax into a page. Normal links inside the loaded content will work fine. But handling events using Jquery for that loaded content will not work. For example, if we have $(‘a’).bind(‘click’, function() { alert(“ok”; }); – this will enable all a tags an alert. But links inside ajax loaded content will not alert. Because normal bind function will not handle events for the content loaded later. But there is a solution. Recently I have read the faq from jquery website: http://docs.jquery.com/Frequently_Asked_Questions. From here we know about Event Delegation and Event Rebinding.

Event Delegation

Event delegation is a technique of capturing events on elements anywhere in the DOM even it is added later. Using live() method we can do this. Consider the following example:

<html>
<head>
  <style>
  #container { width: 800px; margin: auto; }
  p { background:yellow; font-weight:bold; cursor:pointer; 
      padding:5px; }
  span { color:red; }
  </style>
  <script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<div id="container">
  <p class="old">Click me to add new!</p>

  <span>I am a span.</span>
</div>
<script>
    $("p.old").bind("click", function(){
      $(this).after("<p class='new'>I am new! Click me to remove.</p>");
    });
    
     $("p.new").bind("click", function(){
    	$(this).remove();
    });
</script>
</body>
</html>

Here, p.old.click will work, but p.new.click will not. Because the content is added later. To make the second handler working we can use live. Consider this:

<html>
<head>
  <style>
  #container { width: 800px; margin: auto; }
  p { background:yellow; font-weight:bold; cursor:pointer; 
      padding:5px; }
  span { color:red; }
  </style>
  <script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<div id="container">
  <p class="old">Click me to add new!</p>

  <span>I am a span.</span>
</div>
<script>
    $("p.old").bind("click", function(){
      $(this).after("<p class='new'>I am new! Click me to remove.</p>");
    });
   
    $("p.new").live("click", function(){
    	$(this).remove();
    });
</script>
</body>
</html>

We have done only one change, using live instead of bind for the second handler. This will inform the DOM that a new element will be added later and we have to handle the event. Fine, the above is just adding an element. Let us see an example for ajax loaded content:

//page1.htm
<html>
<head>
  <style>
  #container { width: 800px; margin: auto; }
  p { background:yellow; font-weight:bold; cursor:pointer; 
      padding:5px; }
  span { color:red; }
  </style>
  <script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<div id="container">
  <p class="old">Load Content</p>
  <div id="content"></div>
</div>

<script>
    $("p.old").bind("click", function(){
      $("#content").load("page2.htm #content2");
    });
    
    $("p.alert").live("click", function(){
    	alert("I m ok at remote.");
    });
</script>
</body>
</html>

//page2.htm
<html>
<head>
  <style>
  #container { width: 800px; margin: auto; border: 2px solid #ccc;}
  p { background:yellow; font-weight:bold; cursor:pointer; 
      padding:5px; border: 1px solid #CECECE; }
  span { color:red; }
  </style>
  <script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<div id="container">
  <p class="old">Header</p>
  <div id="content2" style="border: 1px solid red;"><p class="alert">What is the alert?</p></div>
</div>

<script>
    $("p.alert").bind("click", function(){
    	alert("I am ok at home.");
    });
</script>
</body>
</html>

Page1 will load page2 using ajax. Using live in page1 we can handle the event for ajax loaded content. Try opening page1 and page2 separately and click on the paragraph, it will invoke different event handlers.
Now, let us see nested ajax loading and event handling:

//page3
<html>
<head>
<style>
  #container { width: 800px; margin: auto; }
  p { background:yellow; font-weight:bold; cursor:pointer; 
      padding:5px; }
  span { color:red; }
</style>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<div id="container">
  <p class="old">Load Content 3-1</p>
  <div id="content"></div>
</div>

<script>
    $("p.old").bind("click", function(){
      $("#content").load("page3-1.htm #container");
    });
    
    $("p.new").live("click", function(){
      $("#content2").load("page3-2.htm #content3");
    });
    
    $("p.alert").live("click", function(){
      alert("Alert from page 3");
    });
</script>
</body>
</html>

//page3-1
<html>
<head>
<style>
  #container { width: 800px; margin: auto; }
  p { background:yellow; font-weight:bold; cursor:pointer; 
      padding:5px; }
  span { color:red; }
</style>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<div id="container">
  <p class="new">Load Content 3-2</p>
  <div id="content2">
  </div>
</div>

<script>
    $("p.new").bind("click", function(){
      $("#content2").load("page3-2.htm #content3");
    });
    
    $("p.alert").live("click", function(){
      alert("Alert from page 3-1");
    });
</script>
</body>
</html>

//page3-2
<html>
<head>
<style>
  #container { width: 800px; margin: auto; }
  p { background:yellow; font-weight:bold; cursor:pointer; 
      padding:5px; }
  span { color:red; }
</style>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<div id="container">
  <p class="new">Load Nothing</p>
  <div id="content3">
  	<p class="alert">Alert?</p>
  </div>
</div>

<script>
    $("p.alert").bind("click", function(){
      alert("Alert from page 3-2");
    });
</script>
</body>
</html>

Page3 loads page3-1 with ajax link. Page3-1 ajax link loads page3-2 and the events of the elements can be handled from page3. That is the beauty of live(). Also each page has its own handlers, we can see the difference by directly opening every pages and click on the paragraph.

Event Rebinding

This is another technique to handle situations like this. But sometimes it will bind events multiple times. So it is better to use live than this technique. In some cases we can not use live. For Example, If we have an lightbox in page2 and we load it inside page1 using ajax, there will be a problem of handling the lightbox event. This is a lightbox page (using http://leandrovieira.com/projects/jquery/lightbox/):

//lightbox.htm
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>jQuery lightBox plugin</title>

	<link rel="stylesheet" type="text/css" href="../style-projects-jquery.css" />    
    
    <!-- Arquivos utilizados pelo jQuery lightBox plugin -->
    <script type="text/javascript" src="js/jquery.js"></script>
    <script type="text/javascript" src="js/jquery.lightbox-0.5.js"></script>
    <link rel="stylesheet" type="text/css" href="css/jquery.lightbox-0.5.css" media="screen" />
    <!-- / fim dos arquivos utilizados pelo jQuery lightBox plugin -->
    
    <!-- Ativando o jQuery lightBox plugin -->
    <script type="text/javascript">
    $(function() {
        $('#gallery a').lightBox();
    });
    </script>
   	<style type="text/css">
	/* jQuery lightBox plugin - Gallery style */
	#gallery {
		background-color: #444;
		padding: 10px;
		width: 520px;
	}
	#gallery ul { list-style: none; }
	#gallery ul li { display: inline; }
	#gallery ul img {
		border: 5px solid #3e3e3e;
		border-width: 5px 5px 20px;
	}
	#gallery ul a:hover img {
		border: 5px solid #fff;
		border-width: 5px 5px 20px;
		color: #fff;
	}
	#gallery ul a:hover { color: #fff; }
	</style>
</head>

<body>

<h2 id="example">Example</h2>
<p>Click in the image and see the <strong>jQuery lightBox plugin</strong> in action.</p>
<div id="gallery">
    <ul>
        <li>
            <a href="photos/image1.jpg" title="Utilize a flexibilidade dos seletores da jQuery e crie um grupo de imagens como desejar. $('#gallery').lightBox();">
                <img src="photos/thumb_image1.jpg" width="72" height="72" alt="" />
            </a>
        </li>
        <li>
            <a href="photos/image2.jpg" title="Utilize a flexibilidade dos seletores da jQuery e crie um grupo de imagens como desejar. $('#gallery a').lightBox();">
                <img src="photos/thumb_image2.jpg" width="72" height="72" alt="" />
            </a>
        </li>
        <li>
            <a href="photos/image3.jpg" title="Utilize a flexibilidade dos seletores da jQuery e crie um grupo de imagens como desejar. $('#gallery a').lightBox();">
                <img src="photos/thumb_image3.jpg" width="72" height="72" alt="" />
            </a>
        </li>
        <li>
            <a href="photos/image4.jpg" title="Utilize a flexibilidade dos seletores da jQuery e crie um grupo de imagens como desejar. $('#gallery a').lightBox();">
                <img src="photos/thumb_image4.jpg" width="72" height="72" alt="" />
            </a>
        </li>
        <li>
            <a href="photos/image5.jpg" title="Utilize a flexibilidade dos seletores da jQuery e crie um grupo de imagens como desejar. $('#gallery a').lightBox();">
                <img src="photos/thumb_image5.jpg" width="72" height="72" alt="" />
            </a>
        </li>
    </ul>
</div>

</body>
</html>

This lightbox will work very clearly directly. But when loaded in another page, we can not handle the lightbox, even using live(). Now we use event rebinding. Event rebinding is binding the new handlers at that time when we adding new ajax content. See this:

<html>
<head>
  <style>
  #container { width: 800px; margin: auto; }
  p { background:yellow; font-weight:bold; cursor:pointer; 
      padding:5px; }
  span { color:red; }
  </style>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<div id="container">
  <p class="old">Load Content</p>
  <div id="content"></div>
</div>

<script>
    $("p.old").bind("click", function(){
      $("#content").load("lightbox.htm", function(){
      	$('#gallery a').lightBox();
      });
    });
</script>
</body>
</html>

Here when we load lightbox.htm we are binding the handler in that page.

These are the two important methods we may need while using ajax. Read all the links given here: http://docs.jquery.com/Frequently_Asked_Questions to explore more.
See the demo, download the examples, make changes and understand better.
:)

About these ads
This entry was posted in Ajax, Jquery, Tutorial and tagged , , , . Bookmark the permalink.

16 Responses to Jquery – Ajax Link inside ajax loaded content problem

  1. Pingback: Jquery – Ajax Link inside ajax loaded content problem « Beschi's Works

  2. brunn says:

    You’re a life saver! I had been struggling with this for the past couple of days and your post did it for me.
    Thanks a lot :)

  3. thisishellow says:

    As brunn said, you’re a life saver! Quite simple but really efficient!
    Thanks!

  4. Thank you for the good writeup. It if truth be told used to be a entertainment account it. Look advanced to more brought agreeable from you! By the way, how can we communicate?

  5. Bayley Trew says:

    Awesome write-up. I have been working on this issue for sooooooo long and all I have to do was put .live infront of the click function . . . . .thank you so much! – I will join everyone else in saying, you are a life-saver ;o)

  6. chknabeel says:

    What if we need to load content via ajax inside the lightbox? I searched the internet but have not found the answer. Can you help me in this?

  7. DaveJ says:

    That is fantastic, thank you for posting this

  8. Daniel says:

    Brilliant article. Been trying to work this out for an hour!

  9. DCH says:

    I found your solution searching in google for “ajax load jquery javascript problem”.

    Thanks for taking the time to publish this. You saved me a great deal of time.

  10. monik says:

    nice write up…
    thanks for your solution

    it really helps a lot….

  11. dudevsfood says:

    I also appreciate this article. Got me out of a “bind”. ;)

    Thanks!

  12. lin says:

    you are really the life saver, thanks a lot,

  13. hug0 says:

    Is this method still working?? I’ve tried it but doens’t seems to work. I even tried your demo “page1 -> loads -> page2″, i click on “what is the alert?” on page1 but does not display the alert.

    Need help please.

  14. papide says:

    From query api:
    “As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers.”

  15. llaabbss says:

    I’m using the following jquery code to be called in dynamically loaded content. But I can’t invoke this script when focus the input_id. Where am I wrong? This code is perfect if it runs in a static page (not being a part of dynamically loaded page).

    jQuery.noConflict();

    jQuery(function() {
    jQuery( “#$input_id” ).autocomplete({
    source: airports_data,
    select: function( event, ui ) {
    jQuery( “#$input_id” ).val( ui.item.label );
    jQuery( “#$input_id_selected” ).val( ui.item.id );
    return false;
    }
    }).data( “autocomplete” )._renderItem = function( ul, item ) {
    return jQuery( “” )
    .data( “item.autocomplete”, item )
    .append( “” + item.label + “” )
    .appendTo( ul );
    };
    });

  16. llaabbss says:

    And I get the same problem if I try to select a date in a datepicker: if this code in a part of dynamically loaded page, it fails.

    jQuery(function() {
    jQuery( “#$date_input_id” ).datepicker({
    showButtonPanel: false,
    onSelect: function(){
    var ChosenDate = jQuery(this).val();
    jQuery(“#ArrivalDate_1″).val(ChosenDate);
    };
    });
    });

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s