How to create shallow copy of element? - javascript

Recently in this question I asked how to find out if style is present in a class. I was told (by skobaljic) that I need to clone element. During the call .clone() of the element (jQuery method) the resulting object contains default styles (e.g. from style sheet) so the inserted styles are not included in the clone. This is how I understood it. But it seems to be strange to clone complete element including all his childern elements which may be hunderets or thousands when I need to detect if 6 style are present. I cheched the jQuery's code for clone method. There is this:
destElements = getAll( clone );
srcElements = getAll( elem );
So the function getAll is called twice.
Then I checked what contains getAll:
var ret = typeof context.getElementsByTagName !== "undefined" ?
context.getElementsByTagName( tag || "*" ) :
typeof context.querySelectorAll !== "undefined" ?
context.querySelectorAll( tag || "*" ) :
[];
From Mozilla manual:
The Element.getElementsByTagName() method returns a live
HTMLCollection of elements with the given tag name. The subtree
underneath the specified element is searched, excluding the element
itself.
Document.querySelectorAll() - Returns a list of the elements within
the document (using depth-first pre-order traversal of the document's
nodes) that match the specified group of selectors. The object
returned is a NodeList.
So it is evident that creating deep copy of the element is pointless and it takes performance. This problem is yet intensified when I need to make deep search/comparison which would lead to excessive waste of resources. I would like to clone the element without it's children element. Is this possible? The clone should contain the default styles just like you do it with .clone(). How to do it?

i believe this can help you:
Source: http://www.w3schools.com/jsref/met_node_clonenode.asp
// Copy the element and its child nodes
var clone_with_child = yourElement.cloneNode(true);
// Copy only the element
var clone_without_child = yourElement.cloneNode(false);

Related

JavaScript HTML element to DOM selector

I have a function that requires a HTML element to perform the action on. I request the DOM selector as a parameter
function(document.body);
where element is the DOM query but somewhere else in the function I need the query as a string. Is it possible to turn the object into it's original string type? And if so, how?
You can do it the other way around. Pass your function a selector string:
functionName('body')
And then retrieve the relevant DOM element using .querySelector():
var el = document.querySelector(string);
The approach you are using is not going to produce the right results consistently in my opinion.
Passing in the element is going to mean that the element must be found beforehand and also is going to practically prevent finding other elements of similar location due to a lack of information.
Passing in a selector is an option, and then using that going forward if you need to find a similar set of elements but sometimes the selector is too complex to be placed in one string - for example if it needs filtering or some other metric.
Your best bet is to accept a callback function that returns the desired element or set of elements when you are dealing with complex selectors or locations for elements. It can simply return the same element each time if it is basic, or if it is more complicated the callback can access the DOM, filter based on some metric, and then return the subset which at times is ideal.
A callback function will provide the full amount of support without needing to always have a conversion to query string which is not always possible for complex structures.
If I understand you correct you could to this
function (elem) {
if (typeof elem === 'string' || elem instanceof String) {
elem = document.querySelector(elem);
}
var target = elem.querySelector(...);
}
To get the HTML string of an element use 'innerHTML'.
Temporary parent:
var div = document.createElement("div");
Append desired element to parent:
div.appendChild(document.body);
Test result:
alert(div.innerHTML);
If you are trying to get the string of the resulting element of 'querySelector()':
div.appendChild(document.body.querySelector('yourClass'));
The temporary parent ensures that you get the tags for the element returned. Otherwise you would only get the string for its child elements. If you want to use 'querySelectorAll()', just loop over the returned node array.

information about this type of selection in jquery $('.myclass',obj).length;

anyone know where can I get information about this Type of selection in jquery
I found it in a .js file and I want to know about it.
I focus on Jquery api doc but in vain I dont find it.
var obj=$('#id1');
var t = $('.slidenews',obj).length;
exactly that what I want to know about.
var t = $('.slidenews',obj).length;
$('...', element) looks for ... in element instead of the whole document. So in this case, it will look for all elements with class slidenews in the #id1 element.
.length returns the number of such elements found
Therefore, if obj contains the element with ID id1, then $('.slidenews',obj).length returns the number of elements with class slidenews that are contained inside the element with ID id1.
Relevant documentation:
jQuery(selector, [context])
selector
Type: Selector
A string containing a selector expression
context
Type: Element or jQuery
A DOM Element, Document, or jQuery to use as context
length
Description: The number of elements in the jQuery object
$('.slidenews',obj) is basically context selector. It will be converted into obj.find('.slidenews') and .length returns the no of such elements
Reference
Selector Context
By default, selectors perform their searches within the DOM starting at the document root. However, an alternate context can be given for the search by using the optional second parameter to the $() function.
It same like:
obj.find('.slidenews')
In your case: obj - must be DOM object. if obj is falsy it will be replaced to document

why does $('el')[0].className work but not $('el').className?

I noticed that className property doesn't work inside jQuery without the index, why is that?
Also, are there other common JS properties / methods that don't work as expected inside jQuery?
HTML:
<div class="par">test</div>
JQuery:
$(function () {
var el = $('.par');
el.className += ' new class'; // doesn't work
el[0].className += ' new class'; // works
});
var el = $('.par'); returns a jQuery object. className is a property on Element and not on jQuery object.
The jQuery object has an array like definition so el[0] returns the underlying Element which has className property.
As far as I know, jQuery doesn't like developer updating its property directly. It simply exposes variety of utility functions for easy developement.
Quoting on a nice comment from David Thomas below,
jQuery methods can only be used on jQuery objects; native DOM properties/methods can only be used on native DOM nodes
Note: var el = $('.par'); returns a collection of Element and el[0] returns the first element in that list.
You could use .addClass to add a class to the element.
To the first element,
el.eq(0).addClass('new_class');
To all elements,
el.addClass('new_class');
More Reading:
https://developer.mozilla.org/en-US/docs/Web/API/element
https://developer.mozilla.org/en-US/docs/DOM/element.className
var el = $('.par');
gives you a jQuery object, which may contain one or more DOM elements.
var el = $('.par')[0];
returns the first DOM object in the selection of that jQuery object. className is a property on a DOM element, not on a jQuery object
$('.par').attr('class');
would be the jQuery way to get the className of the first element.
If you just want to add a particular class to elements matching another class, you can use
$('.par').addClass('testclass');
This will add the test class to all elements with the par class, while your method will only add it to the first element on the page.
Other properties
Also, are there other common JS properties / methods that don't work as expected inside jQuery?
Most dom properties will not work directly on a jQuery object. You can use [0] to get the raw dom element for the first matched element for those. However most of them also have straightforward equivalents in jQuery. The advantage of using the jQuery versions is that they're often simpler, and work consistently across browsers. Native dom properties tend to be faster to access though.
className is part of the api for a DOM element.
var el = $('.par'); will return a jQuery object with an array of elements.
Using el[0] accesses the first element which has access to the api.
jQuery provides an easy method for adding classes to an element or group of elements matched by a selector called addClass. You could use this:
var el = $('.par');
el.addClass('new class');
Also note that it is usually best practice to name variables which contain a jQuery object with $ like this:
var $el = $('.par');
The jQuery DOM object is actually a list of matching elements. Since you're setting a variable on a list of DOM elements, jQuery can't apply them to the entire list. el[0] is the first matched element. (If you have more than one element, using el[0] will only set the first matched element, and if there aren't any matches, el[0] will raise a ValueError.) You should probably use jQuery's builtin class manipulation functions:
el.addClass("new class");
to remove the classes:
el.removeClass("new class");
and to toggle them:
el.toggleClass("new class");
This might not be directly related to the question, but if you're working with jQuery, then you should also be using jQuery's easy to use methods to modify the classname's of all DOM elements within a jQuery object.
http://api.jquery.com/addClass/
http://api.jquery.com/toggleClass/
http://api.jquery.com/removeClass/
$(function () {
var cname = $('.par').attr('class'); // get class attribute
if (!$('.par').hasClass('some-new-class')) {
$('.par').addClass('some-new-class');
}
});

jQuery object and DOM element

I would like to understand relationship between jQuery object and DOM element..
When jQuery returns an element it shows up as [object Object] in an alert.
When getElementByID returns an element it shows up as [object HTMLDivElement]. What does that mean exactly? I mean are both of them objects with a difference ?
Also what methods can operate on jQuery object vs DOM element? Can a single jQuery object represent multiple DOM elements ?
I would like to understand relationship between jQuery object and DOM element
A jQuery object is an array-like object that contains DOM element(s). A jQuery object can contain multiple DOM elements depending on the selector you use.
Also what methods can operate on jQuery object vs DOM element? Can a single jQuery object represent multiple DOM elements ?
jQuery functions (a full list is on the website) operate on jQuery objects and not on DOM elements. You can access the DOM elements inside a jQuery function using .get() or accessing the element at the desired index directly:
$("selector")[0] // Accesses the first DOM element in this jQuery object
$("selector").get(0) // Equivalent to the code above
$("selector").get() // Retrieve a true array of DOM elements matched by this selector
In other words, the following should get you the same result:
<div id="foo"></div>
alert($("#foo")[0]);
alert($("#foo").get(0));
alert(document.getElementById("foo"));
For more information on the jQuery object, see the documentation. Also check out the documentation for .get()
When you use jQuery to obtain an DOM element, the jQuery object returns contains a reference to the element. When you use a native function like getElementById, you get the reference to the element directly, not contained within a jQuery object.
A jQuery object is an array-like object that can contain multiple DOM elements:
var jQueryCollection = $("div"); //Contains all div elements in DOM
The above line could be performed without jQuery:
var normalCollection = document.getElementsByTagName("div");
In fact, that's exactly what jQuery will do internally when you pass in a simple selector like div. You can access the actual elements within a jQuery collection using the get method:
var div1 = jQueryCollection.get(0); //Gets the first element in the collection
When you have an element, or set of elements, inside a jQuery object, you can use any of the methods available in the jQuery API, whereas when you have the raw element you can only use native JavaScript methods.
I just barely started playing with jQuery this last month, and I had a similar question running around in my mind. All the answers you have received so far are valid and on the dot, but a very precise answer may be this:
Let's say you are in a function, and to refer to the calling element, you can either use this, or $(this); but what is the difference? Turns out, when you use $(this), you are wrapping this inside a jQuery object. The benefit is that once an object is a jQuery object, you can use all the jQuery functions on it.
It's pretty powerful, since you can even wrap a string representation of elements, var s = '<div>hello <a href='#'>world</a></div><span>!</span>', inside a jQuery object just by literally wrapping it in $(): $(s). Now you can manipulate all those elements with jQuery.
Most jQuery member Functions do not have a return value but rather return the current jQuery Object or another jQuery Object.
So,
console.log("(!!) jquery >> " + $("#id") ) ;
will return [object Object], i.e. a jQuery Object which maintains the collection which is the result of evaluating the selector String ("#id") against the Document,
while ,
console.log("(!!) getElementById >> " + document.getElementById("id") ) ;
will return [object HTMLDivElement] (or in fact [object Object] in IE) because/if the return value is a div Element.
Also what methods can operate on jQuery object vs DOM element? (1) Can a single jQuery object represent multiple DOM elements ? (2)
(1) There is a host of member Functions in jQuery that pertain to DOM Objects. The best thing to do imo is search the jQuery API documentation for a relevant Function once you have a specific task (such as selecting Nodes or manipulating them).
jQuery documentation
(2) Yes, a single jQuery Object may maintain a list of multiple DOM Elements. There are multiple Functions (such as jQuery.find or jQuery.each) that build upon this automatic caching behaviour.
That's just your browser being clever. They're both objects but DOMElements are special objects. jQuery just wraps DOMElements in a Javascript object.
If you want to get more debug info I recommend you look at debugging tools like Firebug for Firefox and Chrome's built-in inspector (very similar to Firebug).
Besides what has been mentioned, I'd like to add something about why jQuery object is imported according to description from jquery-object
Compatibility
The implementation of element methods varies across browser vendors and versions.
As an example, set innerHTML of element may not work in most versions of Internet Explorer.
You can set innerHTML in jQuery way and jQuery will help you hide the differences of browser.
// Setting the inner HTML with jQuery.
var target = document.getElementById( "target" );
$( target ).html( "<td>Hello <b>World</b>!</td>" );
Convenience
jQuery provides a list of methods bound to jQuery object to smooth developer's experience, please check some of them under http://api.jquery.com/. The website also provides a common DOM manipulation, let's see how to insert an element stored in newElement after the target element in both way.
The DOM way,
// Inserting a new element after another with the native DOM API.
var target = document.getElementById( "target" );
var newElement = document.createElement( "div" );
target.parentNode.insertBefore( newElement, target.nextSibling );
The jQuery way,
// Inserting a new element after another with jQuery.
var target = document.getElementById( "target" );
var newElement = document.createElement( "div" );
$( target ).after( newElement );
Hope this is a supplement.

How to find with javascript if element exists in DOM or it's virtual (has been just created by createElement)

I'm looking for a way to find if element referenced in javascript has been inserted in the document.
Lets illustrate a case with following code:
var elem = document.createElement('div');
// Element has not been inserted in the document, i.e. not present
document.getElementByTagName('body')[0].appendChild(elem);
// Element can now be found in the DOM tree
Jquery has :visible selector, but it won't give accurate result when I need to find that invisible element has been placed somewhere in the document.
Here's an easier method that uses the standard Node.contains DOM API to check in an element is currently in the DOM:
document.body.contains(MY_ElEMENT);
CROSS-BROWSER NOTE: the document object in IE does not have a contains() method - to ensure cross-browser compatibility, use document.body.contains() instead. (or document.head.contains if you're checking for elements like link, script, etc)
Notes on using a specific document reference vs Node-level ownerDocument:
Someone raised the idea of using MY_ELEMENT.ownerDocument.contains(MY_ELEMENT) to check for a node's presence in the document. While this can produce the intended result (albeit, with more verbosity than necessary in 99% of cases), it can also lead to unexpected results, depending on use-case. Let's talk about why:
If you are dealing with a node that currently resides in an separate document, like one generated with document.implementation.createHTMLDocument(), an <iframe> document, or an HTML Import document, and use the node's ownerDocument property to check for presence in what you think will be your main, visually rendered document, you will be in a world of hurt.
The node property ownerDocument is simply a pointer to whatever current document the node resides in. Almost every use-case of contains involves checking a specific document for a node's presence. You have 0 guarantee that ownerDocument is the same document you want to check - only you know that. The danger of ownerDocument is that someone may introduce any number of ways to reference, import, or generate nodes that reside in other documents. If they do so, and you have written your code to rely on ownerDocument's relative inference, your code may break. To ensure your code always produces expected results, you should only compare against the specifically referenced document you intend to check, not trust relative inferences like ownerDocument.
Do this:
var elem = document.createElement('div');
elem.setAttribute('id', 'my_new_div');
if (document.getElementById('my_new_div')) { } //element exists in the document.
The safest way is to test directly whether the element is contained in the document:
function isInDocument(el) {
var html = document.body.parentNode;
while (el) {
if (el === html) {
return true;
}
el = el.parentNode;
}
return false;
}
var elem = document.createElement('div');
alert(isInDocument(elem));
document.body.appendChild(elem);
alert(isInDocument(elem));
You can also use jQuery.contains:
jQuery.contains( document, YOUR_ELEMENT)
Use compareDocumentPosition to see if the element is contained inside document. PPK has browser compatibility details and John Resig has a version for IE.
function isInDocument(query){
return document.querySelectorAll(query).length != 0;
}
// isInDocument("#elemid")

Categories

Resources