Reputation: 16719
The element is being appended to list items when mouse is over them, and detached when mouse is out.
When the element is clicked, it gets detached, and then the list item to which it was part of is removed from the DOM.
My HTML:
<div id="cart">
<ul>
<li> <a data-item="a">item A</a></li>
<li> <a data-item="b">item B</a></li>
<li> <a data-item="c">item C</a></li>
<li> <a data-item="d">item D</a></li>
<li> <a data-item="e">item E</a></li>
<li> <a data-item="f">item F</a></li>
<li> <a data-item="g">item G</a></li>
<li> <a data-item="h">item H</a></li>
</ul>
</div>
And my JavaScript:
function plugin(node, opts){
var self = this;
delKnob = $('<i />').text('×');
this.cart = $(node);
delKnob
.on('click', function(){
var item = $(this).parent().find('[data-item]').data('item');
$(this).detach();
self.remove(item);
});
this.cart
.on('mouseenter', 'li', function(){
delKnob.appendTo(this);
})
.on('mouseleave', 'li', function(){
delKnob.detach();
});
}
plugin.prototype = {
remove: function(item){
var li = this.cart.find('[data-item="' + item + '"]').closest('li');
li.addClass('removing');
setTimeout(function(){
li.remove();
}, 500);
}
};
new plugin('#cart');
I've set up a fiddle example that resembles my code.
The problem is that the click listener from this element also gets removed with the list item, even though the element is being detached before $.remove()
fires, so it shouldn't be affected.
What am I doing wrong here?
Upvotes: 3
Views: 233
Reputation: 30099
You are correct in what you believe is going on, except that when you detach the delKnob
, your mouse immediately enters the li
which contained it, meaning it gets re-attached, so when the li
is removed, delKnob
is still a child and as such gets removed as well.
I tested this by adding a console.log()
to the code:
this.cart.on('mouseenter', 'li', function () {
console.log("delKnob attached!");
delKnob.appendTo(this);
})
Fix this by removing the delKnob
in the setTimeout
:
setTimeout(function () {
li.find('.delKnob').detach();
li.remove();
}, 500);
This assumes adding the class delKnob
to the element.
Demo: http://jsfiddle.net/AHjRN/
As a side note, I would simplify the whole thing and just add a delKnob
to every li
. Then you just show/hide them, and don't have to worry about removing the handler. It also simplifies the code quite a bit:
function plugin(node, opts) {
this.cart = $(node);
this.cart.find('li').append($('<i class="delKnob"/>').text('×').hide());
this.cart.on('click', '.delKnob', function () {
var li = $(this).closest('li').addClass('removing');
setTimeout(function () {
li.remove();
}, 500);
});
this.cart.on('mouseenter', 'li', function () {
$(this).find('.delKnob').show();
})
.on('mouseleave', 'li', function () {
$(this).find('.delKnob').hide();
});
};
Demo: http://jsfiddle.net/F3Qdp/
Upvotes: 6
Reputation: 20491
Instead of binding an event to the delKnob
which is (re)moved around, you could use event delegation and bind an event to the container (this.cart
) that handles any .delKnob
descendant being clicked.
delKnob = $('<i class="delKnob" />').text('×');
this.cart
.on('click', '.delKnob', function(){
var item = $(this).parent().find('[data-item]').data('item');
$(this).detach();
self.remove(item);
});
Upvotes: 1