jQuery won't append a clone declared at document ready - javascript

My issue is that if I create a clone variable on page load, jQuery will only append it once. Weird!
<p>Click to copy</p>
<div id="container">
<div class="element">This is an element!</div>
</div>
$(document).ready(function () {
var obj = $(".element").clone(true);
$("p").click(function () {
//alert(obj); //Just to see if the variable is still an object.
$("#container").append(obj);
});
});
Here is my CodePen link http://codepen.io/anon/pen/Fwduf
This is what I'm getting after 5 clicks:
Click to copy
This is an element!
This is an element!
What I should be seeing:
Click to copy
This is an element!
This is an element!
This is an element!
This is an element!
This is an element!
This is an element!
Interestingly, if I move the variable deceleration inside the click event, the append works completely as expected.

You need to clone it every time
Codepen Demo
$(document).ready(function () {
var obj = $(".element");
$("p").click(function () {
//alert(obj); //Just to see if the variable is still an object.
$("#container").append(obj.clone(true));
});
});
In your case you are creating a new cloned element only once, after that you are just moving the existing element from one place to another

Arun's answer is correct but does not explain why you need to clone your template element each time you want a new element.
One feature of an individual DOM element, that you may not have been aware of, is that it can only have one parent. This makes sense as the DOM tree connects elements up, down, and sideways to each other and only have a single parent-element link (and a single next and single prev sibling element link) but a list of multiple children.
When you clone an element, you create a new DOM element that is effectively a new branch in a DOM tree (if only a small one). Calling append adds the element to its new parent, but it also points a parent link of your clone to its new parent. By appending the same element over and over you are simply changing the parent of a single element (i.e. moving it in the DOM tree).
As the interaction only runs at user interface speed (i.e. mouse click), you might as well simplify your code to:
$("p").click(function () {
$("#container").append($(".element:first").clone(true));
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/7h8MK/1/

Related

Use jQuery to add a picture from one div to another

I want to use jQuery to add an image that is on a div to another div, but when I do it the image disappears from the original div. I would like the image to be copied and not moved. Here is the current code.
$( ".rectangle" ).click(function() {
$('.bigRectangle').css('display','block');
$(".notBig").css('opacity',0.2);
var x = $(this).find('img');
$('.bigRectangle').append(x);
});
This is because a DOM node can only have one parent. Appending it to another element will move it to being a child of the other element. Use the .clone method to clone the img element before appending it.
$('.bigRectangle').append(x.clone());
All you would need to do is perform this:
var x = $(this).find('img').clone();
I would recommend you check out the function clone "https://api.jquery.com/clone/"
In your code you are essentially moving the image, when you assign the image in the variable "x" it holds the dom element in that variable. It is a reference. Matter of fact you are holding all images in the document.
Hope this helps, please let me know.
Mr Alexander

jQuery: Using .after() or .before() adds element to last item in selection only

I've been using jQuery for a while but this is a new one. A simplified example:
HTML
<div class='custom'></div>
<div class='custom'></div>
<div class='custom'></div>
jQuery:
var $customElems = $('.custom'),
$spanOuter = $('<span class="outer"/>'),
$spanInner = $('<span class="inner"/>');
$customElems.each( function() {
$(this).wrap($spanOuter).after($spanInner);
});
JSFiddle:
http://jsfiddle.net/a3ZK8/
I would have expected the 'inner' span to be added to all three elements in the selection but it gets always inserted into the last one only (no matter how many). I tried it with .before(), with and without the chaining, same result. What am I missing??
The problem is you are using a reference to a jQuery object.
Hence you keep moving the object reference around within each iteration.
If you have no events attached or no need for the span to be a jQuery object then just pass the parameter as a HTML string literal instead of an object reference
Cloning a jQuery object that doesn't need to be a jQuery object in the first place is just redundant processing and unnecessary overhead.
Change your jQuery object to a string similar to this:
spanInnerString = '<span class="inner"/>';
and your method like this:
$(this).wrap($spanOuter).after(spanInner);
The result is:
<span class="outer"><div class="custom"></div><span class="inner"></span></span>
<span class="outer"><div class="custom"></div><span class="inner"></span></span>
<span class="outer"><div class="custom"></div><span class="inner"></span></span>
DEMO - Passing parameter as HTML string
Off course, the same goes for the outer span. Don't create jQuery objects unless you have to.
If you must use a jQuery object because you want to attach events to the span or similar, than cloning is the way to go, though make sure you use clone(true, true) then to also clone the attached events.
You need to clone the element. Otherwise, after() will relocate the same element 3 times, which results in it being attached to only the last looped element.
$customElems.each(function () {
$(this).wrap($spanOuter).after($spanInner.clone());
});
Demo: Fiddle
You might ask, "Why would wrap() work?" That's because 'wrap()' internally clones the element.
You're moving the same span from place to place. If you acted on all three divs at once, jquery will instead clone the span.
http://jsfiddle.net/a3ZK8/1/
var $customElems = $('.custom'),
$spanOuter = $('<span class="outer"/>'),
$spanInner = $('<span class="inner"/>');
$customElems.wrap($spanOuter).after($spanInner);
From the documentation for .after:
Important: If there is more than one target element, cloned
copies of the inserted element will be created for each target except
for the last one.
which means the last element will always get the original, while all other selected elements will get a clone. That's why when you acted on one element at a time, it simply moved the same span around.

Using focus on elements inside contenteditable div?

I am trying to use the following code to reference anything focused inside my contenteditable div, which has an id of rt:
var lastfocused;
$("#rt *").focus(function () {
lastfocused = $(this);
});
For some reason, lastfocused always equals $("#rt");, but never anything else which may be inside the contenteditable div. How do I make it so that anything focused inside the contenteditable div will be stored in the lastfocused variable?
Looks like your problem is elsewhere. The above code perfectly works for me:
http://jsfiddle.net/8hZWq/
EDIT
If the children elements aren't inputs as you said, but divs - the focus() method is not applicable to them, as it works only for input, textareas, select etc.
You can also use .click() instead of focus() to store the reference to the last clicked element. Bear in mind though, it also depends to the structure of your elements.
For example if you have multiple levels of containers within children divs, the #ID * selector will actually trigger multiple times each level of children starting from the #ID.
If you like to store reference to only the first level of children of the #ID, you should use #ID > * selector to refer only direct children.
If you like to store the reference to only the very element that was clicked upon regardless of it's level in relation to the container, you should use click event target reference instead:
var clicked;
$('#ID').click(function(event){
clicked = $(event.target);
});
Indeed your problem is because of variable declaration out of the function. Setting it in, in each focus event the 'lastfocused' variable will be re-assigned.
I came later, but if i arrive here someone else can.
Do this:
$("#rt *").focus(function () {
var lastfocused = $(this);
});

JavaScript unexpected object behavior with jQuery

I have two <div> elements, and the following JavaScript code:
var myObject = {
$input: $('<input />'),
insert: function () {
$('div').append(this.$input);
$('div').append(' ');
}
};
myObject.insert();
This, as I expect, produces an <input> element within each of the two <div> elements.
Now when I create a new instance of myObject and call insert() again I will be expecting 4 <input> elements, two in each <div>. Weirdly, I only get 3 <input> elements!
See example code here:
http://jsfiddle.net/FNEax/
You're creating 1 input explicitly:
$input: $('<input />',{value:i}),
...but cloning it implicitly when you try to append it to multiple divs
// 2 divs
$('div').append(this.$input);
Then Object.create doesn't create a new $input, so on the second pass, it appends (moves) the input from the second div (which is actually the original) to the first div, and then does the implicit clone to populate the second.
Here's a jsFiddle example that increments an i variable whenever insert() is called, and adds it as the value of the input. Notice that it is always set at 0.
I also modified it to pass a string to insert so you can see which call each input came from.
The two inputs from the second call both still have the string passed to the first call.
EDIT:
I flipped it around mid explanation, but the concept is the same.
When the second insert() is called, the clone is first created of the original and added to the first div, then the original is appended to the second div (where it already is).
jQuery makes the clones first, then appends the original last.
Here's another jsFiddle example that adds a custom property to the original, then adds some text next to the element with that custom property after each insert(). The text is always added next to that original in the second div.
This is what is happening. From the jQuery docs:
If an element selected this way is inserted elsewhere, it will be moved into the target (not cloned)
If there is more than one target element, however, cloned copies of the inserted element will be created for each target after the first.
So the first time around, since your input isn't anywhere in the DOM it is cloned and inserted into both divs. But, the second time it is called it is removed from the second div, before being cloned and added back into both divs.
At the end of your code, the first div contains both inputs, but the second div only contains the most recent input, since each input was removed from your last div.
http://jsfiddle.net/hePwM/
Once an element is inserted into the DOM, another .append() call with it as the appended content causes it to move within the DOM (docs). Your code creates a jQuery collection with a single input therein, which input has yet to be appended to the DOM. So the first call to insert() appends it to each (using the cloning or copying mechanism internal to jQ).
In the second call, however, this.$input references something which is already in the DOM (due to the first call). Internally, jQuery is each-ing the collection of DIVs and appending the input which lives inside of this.$input. So it adds it, the moves it.
The primary issue is that you're re-appending the same input over and over. Remember that JavaScript generally references existing objects rather than make new ones. That same input element keeps getting re-referenced.
If you want a method to add an input to every DIV, you should simply pass the input markup into append:
$( 'div' ).append( '<input />' );
The wierd behavior is due to the fact you are using a JQuery collection where you shouldn't be. How it even worked in the first place is beyond my skillset.
var myObject = {
input: '<input />',
insert: function () {
$('div').append(this.input);
//$('div').append(' ');
}
};
try each():
var myObject = {
insert: function () {
$('div').each(function(index) {
$(this).append($('<input />'));
$(this).append(' ');
});
}
};
myObject.insert();
myObject.insert();

jQuery ways to dynamically .append a div to the dom, and then find it later without setting an ID, class, or anyway to indentify it

Update: Everyone that contributed, it's well appreciated, you all are very kind and generous and all of you deserve my dear respect. Cheers.
Note: I'm making a simple jQuery tooltip plugin, the tooltip will fire on mouseover. The mouseover will create an instance of the div tool-tip that will be specific to each anchor that launched the div tool-tip. So each anchor with the class .c_tool will have its own created div that will erase after mouseout. Anyway all those details are irrelevant. What is important is how to create a div with .append() or .add() on and then find a way to call it and apply actions to that div without setting an identifier (id), class, or any means to identify it.
I know theres a way you could find the div by counting, so if you gave every created div the same class and then counted them to find that one, however I don't know if this is the most efficient method that is why I'm asking for help.
I'm not going to post the whole plugin script thats unnecessary, so I'll paste a simplified version.
hover me
hover me
$(document).ready(function() {
obj = $('a.c_tool');
obj.mouseover(function() {
/// append div to body it will be specific to each item with class c_tool, however I don't want to set an ID, or CLASS to the appended div
}).mouseout(function() {
/// remove added div without setting ID or class to it.
});
});
Working example:
http://jsfiddle.net/xzL6F/
$(document).ready(function() {
var tooltip;
obj = $('a.c_tool');
obj.mouseover(function() {
var element = $('<div>', {
html: "I'm a tooltip"
});
tooltip = element.appendTo($("body"));
/// append div to body it will be specific to each item with class c_tool, however I don't want to set an ID, or CLASS to the appended div
}).mouseout(function() {
tooltip.remove();
/// remove added div without setting ID or class to it.
});
});
To create a new DOM node you can use the jQuery constructor, like
$(document).ready(function() {
obj = $('a.c_tool');
obj.mouseover(function() {
if(!$.data(this, 'ref')) {
$.data(this, 'ref', $ref = $('<div>', {
html: 'Hello World!'
}).appendTo(document.body));
}
}).mouseout(function() {
$.data(this, 'ref').remove();
});
});
.appendTo() returns the DOM node of invocation (in this case, the newly created DIV) as jQuery object. That way you can store the reference in a variable for instance and access it later.
Referring your comment:
To remove all stored references, you should do this:
$('a.c_tool').each(function(index, node) {
$.removeData(node, 'ref');
});
you can use $.append(
);
http://api.jquery.com/append/
and to find the DOM created dynamically u can use
$("#dynamicallyCreatedDOMid").live("yourCustomTrigger",function(){
});
http://api.jquery.com/live/

Categories

Resources