I use jQuery to attach some plugins in the $(document).ready() handler - for example, $(".date").datepicker(). However, when I load content using $("...html..."), for example from $.ajax(.., success(data){}), or from ajaxForm({target:...}), document.ready() is obviously not called. UPDATE: as pointed out it is calle开发者_运维技巧d but still I don't know what portion/element was loaded.
I can't just do ready() again because it will re-attach plugins second time to elements that have it already. So I have to do it manually in every case, like, I do success(data) { item = $(data); initDatePickerEtc(item); }.
Is there a better way?
There's Live Query plugin that does it for events. Is there something that will allow me to track HTML elements creation and perform actions then? Something like
$.oncreation(".date", function() { $(this).datepicker(); });
// or at least
$.oncreation(function() { $(this).find(".date").datepicker(); });
Great if it will also process existing elements... like Live Query works for both existing at the time of click() call, and the future-created elements.
Note that I'll be happy tracking only elements created by jQuery. So it's either jQuery provides extension point to its html() function or not, I guess. Now, from the jQuery sources it does not:
html: function( value ) {
return value === undefined ?
(this[0] ?
this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
null) :
this.empty().append( value );
},
Maybe if I replace html() so that even 3-rd party plugins (e.g. ajaxForm) will use my version (that will fire $.creation callback) instead of default jQuery one... will it work? There're problems with this approach - it's not only html(), it's append(), etc... and it would be great to get the event only if result of $("") is appended to the document... since when it's in memory I don't need datepicker().
If it is an option for you, you can include a $(document).ready() statement in the returned html. The function passed there will be called after the returned html is rendered.
What you are probably looking for are the W3C mutation events, such as DOMNodeInserted
and DOMNodeRemoved
Unfortunately, they are not supported by all browsers (the IE family of browsers do not support them at all), so we need to look at other ways of achieving cross-browser functionality.
The way that live()
works is to use event delegation and it is possible that you could implement event delegation in your own code. As an example,
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/base/jquery-ui.css" type="text/css" />
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"></script>
<title>Demo</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<script type="text/javascript">
$(function() {
$('.picker').datepicker();
$('button').click(function() {
$(this).prev().before('<br/><input type="text" class="picker" />');
});
$('div.container').click(function(e) {
var target = $(e.target);
if (target.hasClass('picker') && !target.hasClass('hasDatepicker')) {
$(e.target).datepicker().datepicker('show');
}
});
});
</script>
</head>
<body>
<div class="container">
<input type="text" class="picker" />
<br/>
<button>Add a new input</button>
</div>
</body>
</html>
Here we check the event.target
on the container <div>
to see if it has the class picker
and not the class hasDatepicker
(which is added by the datepicker plugin to indicate an input with a datepicker attached). If the event.target
meets the criteria, we bind a datepicker to it and then call datepicker('show')
on it. If the event.target
already has a datepicker attached then clicking on the input will show the datepicker and if event.target
does not have picker
class or no datepicker attached, then nothing will happen.
I chose datepicker as you mentioned it in your question, but the idea of event delegation can be applied in many different circumstances, however, not all events bubble.
You can create a routine that performs the plugin initialization scoped to a particular root jQuery object. Something like this:
function AttachPlugins(jq) {
jq.Find('.date').datepicker();
// other stuff
}
Your document ready handler can call it like:
$(document).ready(function(){
AttachPlugins($(body));
});
While your Ajax handler can call it like this
var newElement = $(html);
AttachPlugins(newEleemnt);
It's not totally automated, but it shouldn't be. The Ajax HTML should be considered "fresh" and unprocessed. Automatically attaching plugins would make me convulse the way SQL triggers do. At least with my approach you reuse the same code that is used to attach the plugins on ready.
精彩评论