user2762294
user2762294

Reputation:

Does AJAX loaded content get a "document.ready"?

Yesterday I had an issue where a .on('click') event handler I was assigning wasn't working right. Turns out it's because I was was trying to apply that .on('click') before that element existed in the DOM, because it was being loaded via AJAX, and therefore didn't exist yet when the document.ready() got to that point.

I solved it with an awkward workaround, but my question is, if I were to put a <script> tag IN the ajax loaded content and another document.ready() within that, would that second document.ready() be parsed ONLY once that ajax content is done being loaded? In other words, does it consider that separately loaded ajax content to be another document, and if so, does having another document.ready() within that ajax-loaded HTML work the way I think it does?

Alternatively; what would be a better way to handle this situation? (needing to attach an event listener to a DOM element that doesn't yet exist on document.ready())

Upvotes: 40

Views: 80171

Answers (6)

Martijn
Martijn

Reputation: 16103

Javascript in the resulting ajax call will not be excecuted (by default) due to safety. Also, you can't directly bind event to non-existing elements.
You can bind an event to some parent that does exist, and tell it to check it's children:

$(document).ready(function(){
    $(document).on('eventName', '#nonExistingElement', function(){ alert(1); }
    // or:
    $('#existingParent').on('eventName', '#nonExistingElement', function(){ alert(1); }
});

Always try to get as close to the triggering element as you can, this will prevent unnessesary bubbling through the DOM


If you have some weird functions going on, you could do something like this:

function bindAllDocReadyThings(){
    $('#nonExistingElement').off().on('eventName', function(){ alert(1); }
    // Note the .off() this time, it removes all other events to set them again
}
$(document).ready(function(){
    bindAllDocReadyThings();
});
$.ajaxComplete(function(){
    bindAllDocReadyThings();
});

Upvotes: 10

Rudresha Parameshappa
Rudresha Parameshappa

Reputation: 3926

try this, that is not working because your control is not yet created and you are trying to attach a event, if you use on event it will work fine. let me know if you face any issues.

$(document).ready(function(){
    $(document).on('click', '#element', function (evt) {
        alert($(this).val());
    });
});

Upvotes: 5

RoboticRenaissance
RoboticRenaissance

Reputation: 1187

JQuery AJAX .load() has a built-in feature for handling this. Instead of simply $('div#content').load('such_a_such.url'); you should include a callback function. JQuery .load() provides room for the following:

$('div#content').load('such_a_such.url',
    { data1: "First Data Parameter",
      data2: 2,
      data3: "etc" },
    function(){ $('#span1').text("This function is the equivalent of");
                $('#span2').text("the $(document).ready function.");
    }
 );

However, you do not need to include the data argument.

$( "#result" ).load( "ajax/test.html", function() { alert( "Load was performed." ); });

http://api.jquery.com/load/

Upvotes: 0

jeteon
jeteon

Reputation: 3729

I'm working on a code-base with a friend that has a similar requirement. The delegated event handler option is definitely best if all you want is to attach event handlers. An alternative, especially if you need to do other DOM processing in your $(document).ready function, is to put the code you want run into a script element at the end of your code. Basically, instead of:

<script type="text/javascript">
  $(document).ready(function() {
    // Your code here
  });
</script>
<!-- rest of dynamically loaded HTML -->

Try swapping the script and the rest of the HTML around so you have:

<!-- rest of dynamically loaded HTML -->
<script type="text/javascript">
  // Your code here
</script>

This forces the browser to only process your code once it has loaded every other DOM element in the dynamically loaded HTML. Of course this means you'll have to make sure the inserted HTML does not have unintended UI consequences by using CSS/HTML instead of JS. Its an old Javascript trick from years gone by. As a bonus, you don't need jQuery for this anymore.

I should mention that in Chromium v34, putting a second $(document).ready call inside a <script> tag in the dynamically loaded HTML seems to wait for dynamically loaded DOM to load and then runs the function as you described. I'm not sure this behaviour is standard though as it has caused me great grief when trying to automate tests with this kind of code in it.

Upvotes: 0

nbar
nbar

Reputation: 6158

To answer your question: No, document.ready will not fire again once a ajax request is completed. (The content in the ajax is loaded into your document, so there isn't a second document for the ajax content).

To solve your problem just add the event listener to the Element where you load the ajax content into it. For example:

$( "div.ajaxcontent-container" ).on( "click", "#id-of-the-element-in-the-ajax-content", function() {
  console.log($( this ));
});

For #id-of-the-element-in-the-ajax-content you can use any selector you would use in $("selector"). The only difference is, only elements under div.ajaxcontent-container will be selected.

How it works: As long as div.ajaxcontent-container exists all elements (if they exist now or only in the future) that match the selector #id-of-the-element-in-the-ajax-content will trigger this click-event.

Upvotes: 36

MonkeyZeus
MonkeyZeus

Reputation: 20737

The answer here is a delegated event:

JSFiddle

JSFiddle - Truly dynamic

jQuery

$(document).ready(function(){
    // Listen for a button within .container to get clicked because .container is not dynamic
    $('.container').on('click', 'input[type="button"]', function(){
        alert($(this).val());
    });

    // we bound the click listener to .container child elements so any buttons inside of it get noticed
    $('.container').append('<input type="button" class="dynamically_added" value="button2">');
    $('.container').append('<input type="button" class="dynamically_added" value="button3">');
    $('.container').append('<input type="button" class="dynamically_added" value="button4">');
    $('.container').append('<input type="button" class="dynamically_added" value="button5">');
});

HTML

<div class="container">
    <input type="button" class="dynamically_added" value="button1">
</div>

Upvotes: 2

Related Questions