jQuery: inserting DOM elements and attaching events
I'm working on a JQuery plugin and I am having a problem when creating DOM elements and attaching a click event to them. My code for creating the DOM elements is shown below:
return this.each(function () {
$this = $(this);
$("<div class=\"" + settings.headingClass + "\">" + $this.attr("title") + "</div>").insertBefore($this).click(function () {
alert($this.attr("title"));
});
});
The values of $this.attr("title")
are correct when rendered on the page and the click event fires on each element however, the alert box always displays the value of $this.attr("title")
for the last element.
Example:
My plugin is being applied to 3 elements with titles "Title1", "Title2" and "Title3". The generated HTML displays these titles correctly but the alert box only displays "Title3" no matter what title element I click on.
Any ideas?
Extra Information
I'm providing some extra information to help with this. I'm creating a basic expander plugin to try and get to grips with JQuery plugin development.
Example of HTML element:
<div class="MyExpander" title="Title1">
This is my expanders content
</div>
JS to create JQuery expander:
$(".QuizExpander").expander({
"headingClass": "ExpanderHeading"
});
Plugin code so far:
(function ($) {
$.fn.e开发者_运维百科xpander = function (options) {
var settings = {
"headingClass": "",
};
if (options) {
$.extend(settings, options);
}
return this.each(function () {
$this = $(this);
$("<div class=\"" + settings.headingClass + "\">" + $this.attr("title") + "</div>").insertBefore($this).click(function () {
alert($this.attr("title"));
});
});
};
})(jQuery);
EDIT: The reason you get this behavior is forgetting to use var
with function-local variables. Failing to use var
creates global variables instead.
Consequently, your $this
in the click()
function was the global one, not the one you defined in each()
.
Original answer: There are some obvious issues with your code, but in principle it should work (at least it does for me, see http://jsfiddle.net/CpeNM/).
Your code sample is either missing the relevant part, or I misunderstood the question. Anyway - here is what I think is wrong with your code in general:
return this.each(function () {
// ALWAYS!!! use the var keyword for local variables (or global ones will be created)
var $this = $(this);
// use the jQuery functions to modify new DOM objects, avoid string-building
var $div = $("<div>").addClass(settings.headingClass).attr("title", $this.attr("title"));
$div.insertBefore($this).click(function () {
// theoretically you could use 'alert($(this).text());' here
alert($this.attr("title"));
});
});
In every walk-trough of this.each()
, $this
gets overridden. So you have to say something like this (if the following this
is a jQuery object, else you'll have to wrap a $()
around it):
return this.before(
$('<div class="' + settings.headingClass + '">' + this.attr("title") + '</div>')
.click(function() {
alert(this.attr("title"));
});
});
return this.each(function () {
$this = $(this);
$("div", $(this)).live('click', function () {
alert($this.attr("title"));
});
$("<div class=\"" + settings.headingClass + "\">" + $this.attr("title") + "</div>").insertBefore($this);
});
Basically, I'm splitting it up into two calls. live() doesn't require the DOM element to exist for the event to apply.
http://api.jquery.com/live/
精彩评论