replaceWith & fadeIn/fadeOut - hover not working afterwards - javascript

I have a task here that requires heavy DOM manipulation. Because this can have a bad impact on the performance, I clone the element, make the changes there and replace the clone with the original.
After replacement, the elements have a hover function.
Because I want faded transition, I do the change like this:
myElement.fadeOut(500, function(){
myClone.hide();
myElement.replaceWith(myClone);
myClone.fadeIn(500);
});
This is working, but after that the hover functionality does not work anymore. When I remove the callback from fadeOut, I can hover again but the timed transitions does not look good anymore.
What can I do about it? Why do the elements lose their hover-functionality when using the callback?

i have a different solution for you. CSS approach:
You can set one of your element's position;
#myElement { top:100px; left:200px; }
#myElement, #myClone { position:absolute; }
jQuery:
$(document).ready(function() {
var myElement = $('#myElement');
var myClone = $('#myClone');
var myEleTop = parseInt(myElement.css('top'));
var myEleLeft = parseInt(myElement.css('left'));
myClone.hide();
myClone.css({'top':myEleTop+'px','left':myEleLeft+'px'});//sets position here
myElement.mouseenter(function() {
myElement.fadeOut(500, function(){
myClone.fadeIn(500);
}
});
myElement.mouseleave(function() {
myClone.fadeOut(500, function(){
myElement.fadeIn(500);
}
});
});
or you can just use appendTo() and remove() methods, i am not really experienced with these methods but try this:
myElement.mouseenter(function() {
myElement.fadeOut(500, function(){
myElement.remove();
myClone.appendTo($('.container'));
myClone.fadeIn(500);
}
});
myElement.mouseleave(function() {
myClone.fadeOut(500, function(){
myClone.remove();
myElement.appendTo($('.container'));
myElement.fadeIn(500);
}
});

When an object is cloned, the clone will no longer have event listeners attached to it. One way to fix it is to attach the event handlers using "on":
$("my-clone-container").on("hover", "my-clone-selector", myHoverHandler);
This way, whenever you add a clone, it will automagically handle hover events as you want it to. See the docs for 'on'.

Related

jQuery-cloned div not responding to click event

The goal is to expand a div to cover the whole screen without destroying the layout.
My current solution looks basically like this:
$( ".box" ).click(function() {
copy = $(this).clone();
copy.addClass("box-active");
// save .box position + size
// maximize div
}
$( ".box-active" ).click(function() {
// minimize div to saved .box position + size
$(this).remove();
}
But the cloned divs will not respond to click events. Is there a way to work around that?
Full code: http://codepen.io/deuxtan/pen/oXQpRy
Use Event delegation for dynamically created class in DoM elements
$(".container").on('click', '.box-active', function() {
if(isFullscreen){
d.width = "100px";
d.height = "100px";
d.top = 0;
d.left = 0;
$(this).animate(d, duration);
isFullscreen = false;
}
});
You need to use .on for dynamically added elements.
$( ".container").on("click", ".box-active", function() {
// ... minimize div ...
$(this).remove();
});
If you want to continue to use "clone", you need to include the "withDataAndEvents" boolean parameter in your call. By default it is false.
So when you write it as
copy = $(this).clone();
you are allowing the default value of false to be passed, and no data or events is included in the close. You need to explicitly pass true.
copy = $(this).clone(true);
For reference, here is the documentation for the clone method.
In your code you did applied coick event on one element, when clonning it, you are not cloning it's events.
That is why you need to attach an event on all div's with class '.box-active'.
$('#parent-of-boxes').on('click', '.box-active', function() {
...
});
This will also work if you apply it on the docuemnt, but it's better to keet it minimalistic as possible, so add it to boxes parent block.
Using on function will apply it to all elements added to DOM that are inside #parent-of-boxes

can you assign draggable like how you add events to a arb node and a selector?

You can do something like:
function myFunct(){/*.....*/}
$("body").on("click", "li.itemlist", function(){
alert("ping");
});
which would have all li.itemlist under body to have the click event.
Is there a way to convert:
var _OPTIONS_ = {
containment: "#stage",
start:function(){/*...*/},
drag:function(){/*...*/},
stop:function(){/*...*/}
};
$("li.itemlist").draggable(_OPTIONS_);
to:
$("body").on("draggable", "li.itemlist", _OPTIONS_);
EDIT: I have not tried the second one. I didnt think it would work because draggable is a JQuery function, not a standard js listener.
No, but there is another way to do it.
$("body").on("mouseenter","li.itemlist:not(.draginit)",function(){
$(this).draggable(_OPTIONS_).addClass("draginit");
})
The first time the element is moused over, the draggable widget will be applied to it.
I'd suggest using something better than body though, such as the ul.

Event For DOM Object Creation

How would one fire an event that fires every time a div is created?
I was thinking something along the lines of this, but clearly not.
$("#content").on("create", "div.block", function () {
$(this).css({"background-color":"#FF0000"});
});
I have discovered MutationObserver (https://stackoverflow.com/a/11546242/165737), however as seen in the comments this does not work in IE.
you could use a mutation event (DOMNodeInserted)... however IE might not fully capable of dealing with that.
http://jsfiddle.net/kasperfish/AAd8f/
$(function() {
$('#btn').click(function(){
$('body').append('<div style="width:30px;height:30px;border:1px solid black"></div>');
});
$(document).on('DOMNodeInserted', function(e) {
$(e.target).addClass('blue');
});
});
I like to note that it is better to use callback events instead of listening to the DOM. You'll need to write a callback after a div is inserted in the DOM. I don't think there is an other (non-hacky) way to accomplish this.
You may try something like this instead of MutationObserver to get notified when ever a div.block has been added to the div#content
$(function(){
var c = $('#content'), l = c.find('.block').length;
setInterval(function(){
var lOld = l;
if(c.find('.block').length > lOld) {
l = c.find('.block').length;
c.find('.block').css({"background-color":"#FF0000"});
}
}, 100);
});
An example and here is another example with multiple Background color effect.

fadeToggle next element in on hover

I have the following code to show the next element in the dom on click, I would like to convert this same code into something I could use for a simple hover event. Does jQuery have a simple method to do something like this or should I be using .bind() to mouseover and mouseout events? I know this should be simple, I am probably just not thinking clearly.
$('#el').click(function(e){
e.preventDefault();
var $prevEl = $(this).parent().find('.prev-el');
$prevEl.fadeToggle();
});
One thing to mention is I would like the $prevEl to stay visible after hovering the triggering #el element. What is the best way to go about this?
Thank you in advance,
DT
You can use $('#el').mouseover(... instead of $('#el').click(..., but you should use fadeIn instead of fadeToggle when you're using mouseover:
$('#el').mouseover(function(e) {
var $prevEl = $(this).parent().find('.prev-el');
$prevEl.fadeIn();
});
http://jsfiddle.net/mblase75/eXjTb/3/
If you want it to fade back out on mouseout, though, use .hover as a shorthand way to combine the two and keep the fadeToggle:
$('#el').hover(function(e) {
var $prevEl = $(this).parent().find('.prev-el');
$prevEl.fadeToggle();
});
http://jsfiddle.net/mblase75/eXjTb/2/
this should work:
$('#el').mouseover(function(){
$(this).parent().find('.prev-el').fadeIn();
});
By the way, you can use .next() and .prev() instead of .parent().find(...) (depending on your html)

Temporary Onmouseover

Css "hover" selector applys a temporary style to an element, but it isn't definitive:
div:hover {
background-color: red;
}
I can do the same thing with javascript but it is a bit complicate and impossible for several elements:
var elem = document.getElementsByTagName ("div")[0];
elem.onmouseover = function () {
this.style.backgroundColor = "red";
}
elem.onmouseout = function () {
this.style.backgroundColor = "transparent";
}
Is there a better way ? Something like this:
document.getElementsByTagName ("div")[0].ontemporarymouseover = function () { // LoL
this.style.backgroundColor = "red";
}
Thanks
No, there is no way to apply styles that go away by themselves.
Eventhough the CSS contains only one definition, it actually corresponds to the two state changes that triggers onmouseover and onmouseout. When the pointer enters the element, the :hover pseudo class is added to it making the CSS rule apply. When the pointer leaves the element, the :hover pseudo class is removed making the CSS rule no longer apply.
In JavaScript this behaviour can only be handled by listening to the mouseover and mouseout DOM events, as you did in your second example. However it is recommended to handle hovering styles with CSS, as in your first example.
// jQuery 'Temporary mouseevents'
$("element").bind
({
mouseover:
function ()
{
},
mouseout:
function ()
{
}
});
$("element").unbind('mouseover mouseout');
I hope this is a good approach for what you need.
I believe that if you use the jQuery JavaScript framework, you can do this:
$('div:first').hover(function(){
$(this).css('background-color','red');
},function(){
$(this).css('background-color','white');
});

Categories