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.
Related
im trying to replace various elements with another inside a jquery .each loop and give them on click events to their child nodes, but it does not work, here is my code.
var replacer = function () {
var elementbody = "<div class='Container'><div class='Button'></div></div>";
$('.myclass').each(function (index, element) {
$(element).replaceWith(elementBody);
$(element).find('.Button').click(function () {
//------------------To do on click event------------------//
});
};
After you use
$(element).replaceWith(...);
element still refers to the old element, not the elements that have replaced it. So $(element).find('.Button') doesn't find the button you just added.
Instead of adding the handler to each element that you add, use delegation to bind a handler just once, as explained in Event binding on dynamically created elements?
$("someSelector").on("click", ".Button", function() {
...
});
You can use a delegate as Barmar suggests or you could provide yourself with a new jquery object that references your new content before running the replaceWith
Something like this, maybe:
new_element = $('<div><button>Hello World</button></div');
$(element).replaceWith(new_element);
new_element.find('button').on('click', function(e) {
console.log(e);
});
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
I'm working with Prototype on a script to detect all Select Tags under a Div and then add an event/observer on each one!
Here is the code to find the Elements I need:
Event.observe(window, 'load', function() {
var tab=$("product-options-wrapper").descendants();
var attCode=[];
var j=0;
for (i=0;i<tab.length;i++) {
if (tab [i].tagName =="SELECT") {
attCode[j++]=tab[i].id
}
}
});
I have all the Ids I need.
How can I add an observer (on change) for each one?
$(id).on("change", function(event) {
alert(id+"__"+$(id).value);
});
Prototype supports event delegation out of the box. Event.on takes on optional second selector parameter. So in your case:
$("product-options-wrapper").on('click', 'select', function(event, element) {
// This callback will only get fired if you've clicked on a select element that's a descendant of #product-options-wrapper
// 'element' is the item that matched the second selector parameter, in our case, the select.
....
});
That parameter can be any CSS selector string:
$('my-element').on('click', '.some-class', function(event, element) { ... });
Check out Element.select, too. That will condense the code in your original question down to essentially one line:
$("product-options-wrapper").select('select');
This one seems kind of confusing because your selector string is 'select' (you want all SELECT elements under #product-options-wrapper). You could also do:
$$('#product-options-wrapper select');
These both return an array of matched elements.
HTH
You only need a click handler on the div (in other words, use event delegation)
var tab = $("product-options-wrapper");
tab.on('click',function(e){
e = e || event;
if ( /^select$/i.test((e.target || e.srcElement || {}).tagName) ){
//do stuff
}
});
That should do. Please post your html or even better a jsfiddle if you need more help.
$(function(){
$('#product-options-wrapper select').on("change", function(e) {
alert(id+"__"+$(this).val());
});
});
I guess you forgot the . at the beginning of product-options-wrapper to indicate its a class? Or is it really a tag?
I've been struggling with what seems to be a simple problem for a few hours now. I've written a REGEX expression that works however I was hoping for a more elegant approach for dealing with the HTML. The string would be passed in to the function, rather than dealing with the content directly in the page. After looking at many examples I feel like I must be doing something wrong. I'm attempting to take a string and clean it of client Events before saving it to our Database, I thought jQuery would be perfect for this.
I Want:
Some random text click here and a link with any event type
//to become:
Some random text click here and a link with any event type
Here's my code
function RemoveEvilScripts(){
var myDiv = $('<div>').html('testing this Do it! out');
//remove all the different types of events
$(myDiv).find('a').unbind();
return $(myDiv).html();
}
My results are, the onClick remains in the anchor tag.
Here's a pure Javascript solution that removes any attribute from any DOM element (and its children) that starts with "on":
function cleanHandlers(el) {
// only do DOM elements
if (!('tagName' in el)) return;
// attributes is a live node map, so don't increment
// the counter when removing the current node
var a = el.attributes;
for (var i = 0; i < a.length; ) {
if (a[i].name.match(/^on/i)) {
el.removeAttribute(a[i].name);
} else {
++i;
}
}
// recursively test the children
var child = el.firstChild;
while (child) {
cleanHandlers(child);
child = child.nextSibling;
}
}
cleanHandlers(document.body);
working demo at http://jsfiddle.net/alnitak/dqV5k/
unbind() doesn't work because you are using inline onclick event handler. If you were binding your click event using jquery/javascript the you can unbind the event using unbind(). To remove any inline events you can just use removeAttr('onclick')
$('a').click(function(){ //<-- bound using script
alert('clicked');
$('a').unbind(); //<-- will unbind all events that aren't inline on all anchors once one link is clicked
});
http://jsfiddle.net/LZgjF/1/
I ended up with this solution, which removes all events on any item.
function RemoveEvilScripts(){
var myDiv = $('<div>').html('testing this Do it! out');
//remove all the different types of events
$(myDiv)
.find('*')
.removeAttr('onload')
.removeAttr('onunload')
.removeAttr('onblur')
.removeAttr('onchange')
.removeAttr('onfocus')
.removeAttr('onreset')
.removeAttr('onselect')
.removeAttr('onsubmit')
.removeAttr('onabort')
.removeAttr('onkeydown')
.removeAttr('onkeypress')
.removeAttr('onkeyup')
.removeAttr('onclick')
.removeAttr('ondblclick')
.removeAttr('onmousedown')
.removeAttr('onmousemove')
.removeAttr('onmouseout')
.removeAttr('onmouseover')
.removeAttr('onmouseup');
return $(myDiv).html();
}
Why is this "copy"(click) wrong, it binds all the previous handlers as well:
var add = function(element) {
var ele = element.clone(true);
$('.container').append(ele);
$('.copy', new).click(function(){ add(ele); });
}
Idea: I want to have an element text next to a "copy" button.
When I click "copy", it clones the current row and append it to the container.
But this seems to be recursive...
The true parameter says:
Normally, any event handlers bound to the original element are not copied to the clone. The optional withDataAndEvents parameter allows us to change this behavior, and to instead make copies of all of the event handlers as well, bound to the new copy of the element.
So you keep adding click event handlers to the .clone element. Depending on your actual case, just don't bind the event handler again:
var add = function(element) {
var cloned = element.clone(true);
$('.container').append(cloned);
}
$('.container .copy').click(function(){
add($(this).closest('tr'));
});
(I used $(this).closest('tr') to get the parent row. Obviously you have to adjust it to your needs.)
Update:
Or don't pass true:
var add = function(element) {
var cloned = element.clone();
$('.container').append(cloned);
$('.copy', cloned).click(function(){ add(cloned); });
}
new is JS keyword. Change it to something else and it should work.
( Your code does not have call of add() except of from itself. So it is not clear how code gets there initially. And recursive declaration of functions as in your code is a path to programmers hell )