jQuery-cloned div not responding to click event - javascript

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

Related

Re-attach an detached div [duplicate]

I have detached a div and want to re-attach it when clicking on a button.
Here's the code:
$('#wrapper').detach();
$("#open_menu").click(function(){
ATTACH HERE !!!
});
Any help will be appreciated.
var el = $('#wrapper').detach();
$("#open_menu").click(function(){
$(this).append(el);
});
I needed a solution that would work even if there are other elements after the target element to detach and then reattach. This means that append may not be reliable because it would move that element back to the end of its parent. I had to use a placeholder which may not be the most elegant solution, but I haven't found another way..
var $wrapper = $('#wrapper')
, $placeholder = $('<span style="display: none;" />')
.insertAfter( $wrapper )
;
$wrapper.detach();
$("#open_menu").on('click',function(){
$wrapper.insertBefore( $placeholder );
$placeholder.remove();
});
To make this more reusable, it might be better to wrap it in a jQuery plugin:
(function($){
$.fn.detachTemp = function() {
this.data('dt_placeholder',$('<span style="display: none;" />')
.insertAfter( this ));
return this.detach();
}
$.fn.reattach = function() {
if(this.data('dt_placeholder')){
this.insertBefore( this.data('dt_placeholder') );
this.data('dt_placeholder').remove();
this.removeData('dt_placeholder');
}
else if(window.console && console.error)
console.error("Unable to reattach this element because its placeholder is not available.");
return this;
}
})(jQuery);
Usage:
var $wrapper = $('#wrapper').detachTemp();
$("#open_menu").on('click',function(){
$wrapper.reattach();
});
if you want your item to attach at the beginning of the element you could use .prepend()
otherwise you could attach it using append().
in your case it would be:
var $wrapper = $('#wrapper').detach();
$("#open_menu").click(function(){
//ATTACH HERE !!!
$(this).prepend($wrapper); // or $(this).append($wrapper);
});
I hope it helps :)
I think this is largely a matter of recording the index of the element that will be detached, before detaching it, then using that index for determining where to re-attach the element. Consider the following "repl" https://repl.it/#dexygen/re-attach and the code below. The setTimeout is merely so you can see the element in the page before it gets detached, and a couple of elements have been renamed. I wonder if siblings can be used instead of parent().children() but am concerned what happens in the event the detached sibling is the only element among siblings, and we need a reference to parent anyway, for prepending if index === 0.
setTimeout(function() {
var bar = $('#bar');
var parent = bar.parent();
var index = parent.children().index(bar);
bar.detach();
$("#re-attach").one('click', function() {
if (index === 0) {
parent.prepend(bar);
}
else {
parent.children().eq(index-1).after(bar);
}
});
}, 5000);
$(function(){
var detached = $('#element_to_detach').detach();
// Here We store the detach element to the new variable named detached
$('.element_after_which_you_need_to_attach').after(detached);
});
var $wrapper = $('#wrapper').detach();
$("#open_menu").click(function(){
$(this).append($wrapper[0])
});
How about prepend() the detached element after assigning it to a variable, ie.
var det_elem = $('#wrapper').detach();
$("#open_menu").click(function(){
$(this).prepend(det_elem);
});
prepend() will attach at the beginning of the element.
jQuery does not offer an attach method. Consider that detach is the equivalent of permanently deleting an item from the Dom. If you believe that you might want to remove and later bring back an element, consider the following options:
Use the toggle method. To hide and unhide elements from the page.
If you must absolutely remove the item from the Dom, consider using the jQuery clone method, to first make a copy of the specified element, which you can then later reintroduce the element copy back to the Dom.
The above are not the only two ways to accomplish this, however, they are simply and would likely not require much code changes on your end.

how to add data dynamically in jQuery? [duplicate]

This question already has an answer here:
How to add data dynamically with jQuery?
(1 answer)
Closed 8 years ago.
Can you please tell me how to add data dynamically? I am not able to make same as static.
http://jsfiddle.net/eHded/1537/
Please check this fiddle and open panel it show menu as well as submenu options.
Now I need to make same on button click. I have add button. I want add menu option (which is submenu of Additem in panel) can we do this.
I get the button click event, but that is not working fine.
http://jsfiddle.net/eHded/1538/
$('#add').click(function(){
// alert('e')
$('#tree li').append('<ul><li> <span>jjjj</span><ul>')
var tree = $('#tree').goodtree({'setFocus': $('.focus')});
})
Try this instead:
$('#add').click(function(){
var data = $('#tree li').html();
$('#tree li').html(data+'<ul><li> <span>jjjj</span><ul>')
var tree = $('#tree').goodtree({'setFocus': $('.focus')});
});
JsFiddle
You did not close your <ul> and <li> tag.
Also, you probably don't want to add the new element to every <li> in the tree.
Try the following instead (http://jsfiddle.net/eHded/1541/):
$(function() {
var tree = $('#tree').goodtree({
'setFocus': $('.focus')
});
$('.slider-arrow').click(function() {
var anchor = this;
var removeClass = "show";
var addClass = "hide";
var diff = "+=300";
var arrows = "«";
if ($(anchor).hasClass("hide")) {
diff = "-=300";
removeClass = "hide";
addClass = "show";
arrows = "»";
}
$(".slider-arrow, .panel").animate({
left: diff
}, 700, function() {
// Animation complete.
$(anchor).html(arrows).removeClass(removeClass).addClass(addClass);
});
});
$('#add').click(function() {
$('#tree').children().last().append('<ul><li><span>jjjj</span></li></ul>');
$('.goodtree_toggle').off();
$('#tree').goodtree({
'setFocus': $('.focus')
});
})
});
There also seems to be a problem with the goodtree plugin you are using.
The items only expand every second time you click them.
Ideally the plugin would use event delegation to make sure that the expanding still works even if you change the tree, without having to re-initialize. Since you re-initialize the tree after every insertion, there are multiple event handlers attached to the nodes. So when you have an odd number of nodes inserted, it will toggle the element an even times (since you initialized it in the very beginning when it was empty), giving you no result.
You can fix it by removing all event handlers on the toggle before you re-initialize:
$('.goodtree_toggle').off();
I would really look for a better plugin instead.

replaceWith & fadeIn/fadeOut - hover not working afterwards

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'.

jquery or js code to obtain exact node data for currently selected form item/text/image in a web page

I want to obtain the exact details for the item on a web page that has been clicked on, using jquery.
That item can be a form item (like a checkbox, text box, text area etc) or section of text (in a paragraph or div or other) or list or image ...
What I figured out is the following--
$(function(){
$('*')
.bind('click', function(event) {
//now obtain details of item that has been clicked on...
});
});
Now, I want the exact details- viz the div id/form id/paragraph #, ie all details for that particular item. How do i get this data? I understand that this data is available in the DOM but I just dont know how to get it in this particular case...
Probably the best way to do to use the target property of the event. By default, this returns a non-jQuery object, which isn't particularly useful, however wrapping it in $() solves this issue:
$(function() {
$(document).bind('click', function(event) {
var element = $(event.target);
alert(element.height()); // Get height
alert(element.attr('id')); // Get ID attribute
// ...
});
});
If you want to fix your current method, inside your click() handler, you can access the properties of that element using .attr(), and friends:
$(function() {
$('*').bind('click', function(event) {
alert($(this).height()); // Get height
alert($(this).attr('id')); // Get ID attribute
// ...
});
});
$(this) in the scope of the function references the element that was clicked. There is a list of functions that will return attributes here and here in the jQuery docs. $.attr('id') will return the element's ID, among other things, and $.data() will return data-* attributes.
To get attributes of parent elements, simply use $(this).parent(). For example, to get the ID of the form that contains the clicked element, use $(this).closest('form').attr('id');. Everything is relative to the clicked element ($(this)), so you can just use the DOM traversal functions.
However, using $('*').bind() is incredibly inefficient; you're binding an event handler to every element on the page, when really you should delegate events with .on() (jQuery 1.7+):
$(function() {
$('body').on('click', '*', function(event) {
alert($(this).height()); // Get height
alert($(this).attr('id')); // Get ID attribute
// ...
});
});
This approach only binds one event to <body> instead of an event to every element on the page.
Use the target of click event on page
$(document).click(function(event){
/* store native dom node*/
var tgt=event.target;
/* store jQuery object of dom node*/
var $tgt=$(tgt);
/* example element details*/
var details={ id : tgt.id, height: $tgt.height(), tag : tgt.tagName}
console.log( details)
})
Look at the event.target, and then you can use jQuery's .parents() method to look at every ancestor:
$(document).on('click', function(event) {
var $t = $(event.target); // the element that was actually clicked
var $p = $t.parents(); // the target's parents
var $form = $p.filter('form').first(); // the enclosing form, if it exists
});

jQuery: Any way to "refresh" event handlers?

I have two divs, one that holds some stuff and the other with all possible stuff. Clicking on one of the divs will transfer items to the other div. The code I came up with is:
$("#holder > *").each(function() {
$(this).click(function(e) {
$(this).remove();
$("#bucket").append(this);
});
});
$("#bucket > *").each(function() {
$(this).click(function(e) {
$(this).remove();
$("#holder").append(this);
});
});
This one works perfectly, except that the event handlers need to be refreshed once I append or remove elements. What I mean is, if I first click on an element, it gets added to the other div, but if I click on this element again, nothing happens. I can do this manually but is there a better way to achieve this?
Try jquery live events .. the $.live(eventname, function) will bind to any current elements that match as well as elements added to the Dom in the future by javascript manipulation.
example:
$("#holder > *").live("click", function(e) {
$(this).remove();
$("#bucket").append(this);
});
$("#bucket > *").live("click", function(e) {
$(this).remove();
$("#holder").append(this);
});
Important:
Note that $.live has since been stripped from jQuery (1.9 onwards) and that you should instead use $.on.
I suggest that you refer to this answer for an updated example.
First, live is deprecated. Second, refreshing isn't what you want. You just need to attach the click handler to the right source, in this case: the document.
When you do
$(document).on('click', <id or class of element>, <function>);
the click handler is attached to the document. When the page is loaded, the click handler is attached to a specific instance of an element. When the page is reloaded, that specific instance is gone so the handler isn't going to register any clicks. But the page remains so attach the click handler to the document. Simple and easy.
Here you go, using the more intuitive delegate API:
var holder = $('#holder'),
bucket = $('#bucket');
holder.delegate('*', 'click', function(e) {
$(this).remove();
bucket.append(this);
});
bucket.delegate('*', 'click', function(e) {
$(this).remove();
holder.append(this);
});
EDIT: don't use live, it be deprecated!
Take advantage of the fact that events bubble. Using .on():
var = function( el1, el2 ) {
var things = $('#holder, #bucket');
things.each(function( index ) {
// for every click on or in this element
things.eq(index).on('click', '> *', function() {
// append will remove the element
// Number( !0 ) => 1, Number( !1 ) => 0
things.eq( Number(!index) ).append( this );
});
});
any click on any element (existing at the time of bind or not) will bubble up (assuming you haven't manually captured the event and stopped propagation). Thus, you can use that event delegation to bind only two events, one on each container. Every click that passed the selector test of the 2nd argument (in this case, > *, will remove that element and then append it to the alternate container as accesesed by things.eq( Number(!index) )
Have you looked at jQuery's live function?
The most Efficient way (dont load all event for all elements) it:
//NORMAL FUNCTION
function myfunction_click(){
//custom action
}
$('id_or_class_of_element').on('click', myfunction_click);
//LOAD OR REFRESH EVENT
$(document).on('click', 'id_or_class_of_element', myfunction_click);

Categories