If I have <element id="blah" class="blah" attr="blah"> (edit: and I have NO other elements in the DOM, just this one)
Then are these jQuery objects absolutely equivalent:
$("#blah")
$(".blah")
$("[attr=blah]")
Is it the case that the query is executed when the object is created and after that it is irrelevant what query was used?
Edit: Does the original query used have any impact later on anything I might do with the resulting jQuery object? Are the 3 resulting objects above identical? Are they any lasting effects from the actual query I had used? (e.g., when I do something with that object later)
Each may get the element, however they do it in different ways because they are different selectors.
The id selector #
$("#blah")
This will return a jQuery object with 1 element in it (the element you list). The benefit of using an id is that it will only return your one element if it exists, and is fastest as a result of ids being expected to be unique.
The class selector .
$('.blah')
This will return a jQuery object with an array of elements in it (including the element you lsit), but also with any other element that has this class. Since there is no combination with this selector, it will be slower than a straight id lookup because it must inspect every element on the page for this class.
The attribute selector []
$("[attr=blah]")
Much like the class selector, this will return an array of elements. It also must inspect every element.
These may look the same if there is only one match when a jQuery function call is used. The reason for that happening is jQuery will look to see if there is an array of elements matched, and then internally use $.each on the set to apply the jQuery function call to them. The benefit is that this makes sets of elements responds very similarly to single elements which are wrapped by the jQuery object.
Here is a whole list of selectors jQuery supports:
http://api.jquery.com/category/selectors/
The element will match all three selectors, but it does not make the three selectors absolutely equivalent because they all have different matching criteria (one looks for an ID, one looks for a class name, and one looks for an arbitrary attribute). In particular, the class and attribute selectors can return more than one element, since unlike an ID selector they do not imply uniqueness of an element.
Even if you can guarantee that this element will be the only one matched by all three selectors, every call to $ always yields a unique jQuery object, even if the resulting jQuery objects encapsulate the same DOM element.
The query returns an array of html elements. In this specific case all queries return the same array. There is no way the original query will have an effect later.
Related
I am a novice and trying to design both relative CSS selectors and JSPath to run my automation scripts.
While on the way, I could find the return statements are different between these two. Please check the below example. Could someone tell what changes I need to make in JSPath to keep the results same as relative CSS selectors.
Result of Relative CSS selector.
Result of Relative JSPath.
JS just returns first element while the css selectors returned multiple above. What changes do I need to make in JS to keep the results same.
Document.querySelector()
The Document method querySelector() returns the first WebElement within the document that matches the specified selector, or group of selectors. If no matches are found, null is returned.
Note: The matching is done using depth-first pre-order traversal of
the document's nodes starting with the first element in the document's
markup and iterating through sequential nodes by order of the number
of child nodes.
Syntax:
element = document.querySelector(selectors);
Document.querySelectorAll()
The Document method querySelectorAll() returns a static NodeList representing a list of the document's elements that match the specified group of selectors.
Note: Although NodeList is not an Array, it is possible to
iterate over it with forEach(). It can also be converted to a real
Array using Array.from(). However, some older browsers have not implemented NodeList.forEach() nor Array.from(). This can
be circumvented by using Array.prototype.forEach().
Syntax:
elementList = parentNode.querySelectorAll(selectors);
Using CssSelector
While using a xpath or a css-selectors would return a list of the document's elements that match the specified group of selectors.
Conclusion
As discussed above, when you use querySelector() only the first matching element is returned. If your usecase is to return all the matching element, you need to use querySelectorAll() as:
document.querySelector("div[slot^='Learner']>div>div>span")
You have to use
document.querySelectorAll();
I need help with getting elements by querySelectorAll function.
When I call it and I pass a string as parameter of this function with multiple elements separated with commas, it will return me a NodeList with nodes but, they are sort by first-depth traversal pre-order (which should be as they are positioned in document body). And I have a problem when I want to call a method to return values of more elements in document saved in Array. So I call this
$('#textinput, #someotherinput').value();
where element with id #someotherinput is positioned above the element #textinput, but the result after querySelectorAll is this:
[input#someotherinput, input#textinput]
0: input#someotherinput
1: input#textinput
length: 2
__proto__: NodeList
and I need to sort them way I did when I called $(), because when I need to use values, I look just at $('#textinput, #someotherinput') and it's annoying to find out an order of the elements in document body and use returned array with values of those elements when I don't know what is saved in first (0th) position in array. And yes, I know that querySelectorAll is traversal pre-order function. So, how to sort (easy as possible) elements to MY order?
There is no simple way to determine if an element would be matched by a selector. You would have to reimplement the entire rule matching system, so the easiest way is to simply use the selector to query for the elements.
The simplest way to get the elements in the order that you like, would be to split the selector into its subselectors, do a query for each, then put the results together by eliminating duplicate element references.
How to can I treat the return value of jQuery functions that would return a bunch of DOM elements. E.g. I'm using the .nextAll() function, that returns a bunch of elements, does it? Can I store the return value in a JS array? Sooner or later I want to iterate through those elements. I know there's the jQuery .each() function that would help me out here. Nevertheless, for training and understanding issues I first want to do it step by step.
I'm pretty sure, this basic question is answered somewhere, but I searched for an answer and did not find anything useful for me. Maybe I didn't find the right words. So please be kind.
jQuery functions typically returns a bunch of DOM elements, it masquerades as an array.
If you run something like:
$('p').css('background-color', 'red');
jQuery will build an array of all p elements, and then applies the css() function to each of them.
If you want a single DOM item, use get with an index:
$( "li" ).get( 0 )
So, .nextAll() also typically returns a number of elements, so it is behaving just like jQuery typically does.
each() is a handy-dandy function that operates on arrays, so it will of course operate just fine on jQuery objects:
$('li + li').nextAll().each(function(i){
//glorious code
});
You could also do this:
var nexts = $('li + li').nextAll();
$.each(nexts, function(i){
//Glorious code!!
});
Hope that makes things clearer!
You can just assign it to a variable:
var $els = $(selector).nextAll();
This way, $els will be a jQuery wrapper (array-like object) of the elements.
If you want to have an array of the elements instead, you can use
var arr = [].slice.call($els);
As the documentation of .nextall() says, it returns jQuery
A jQuery object contains a collection of Document Object Model (DOM)
elements that have been created from an HTML string or selected from a
document. Since jQuery methods often use CSS selectors to match
elements from a document, the set of elements in a jQuery object is
often called a set of "matched elements" or "selected elements".
The jQuery object itself behaves much like an array; it has a length
property and the elements in the object can be accessed by their
numeric indices [0] to [length-1]. Note that a jQuery object is not
actually a Javascript Array object, so it does not have all the
methods of a true Array object such as join().
How can I remove all the elements with a specific tag name using Javascript. For example, I did the following:
var els = document.getElementsByTagName("center");
and it returned an array of all the center elements. How may I remove all these elements?
Coming from Remove all child elements of a DOM node in JavaScript and JavaScript DOM remove element I know that I can loop through els, find the parent of each element and then remove that specific node. But is there anyother way provided by javascript. Like we can do $('center').remove() in jquery and it removes all the elements with center tag. Anything similar to that in Javascript?
With the mention that you still loop over the elements (there is no way to avoid that), you can do this:
Array.prototype.slice.call(document.getElementsByTagName('center')).forEach(
function(item) {
item.remove();
// or item.parentNode.removeChild(item); for older browsers (Edge-)
});
DEMO: http://jsbin.com/OtOyUVE/1/edit
Some notes on slice:
document.getElementsByTagName doesn't return an array, it returns a live list with a length
property. That is why it is needed to first convert it into an array (Array.prototype.slice does that for any object with the length property). By doing that you eliminate the problem of the list being live (gets updated when you change the DOM) and you also get the other array functions to work (like forEach) which have a more functional syntax for looping.
"it returned an array of all the center elements."
Well, it returned an array-like object (a live NodeList or an HTMLCollection depending on the browser).
"How may I remove all these elements?"
You have to loop through the list removing them one at a time as you mentioned later in your question. If you find yourself doing that a lot, encapsulate the looping inside a function so that you don't have to repeat it.
"we can do $('center').remove() in jquery and it removes all the elements with center tag. Anything similar to that in Javascript?"
jQuery is a collection of JavaScript functions, so it can't do anything JavaScript can't do. jQuery's .remove() method (like most other jQuery methods) will loop internally, it just saves you having to think about it. So that comes back to what I already mentioned above, encapsulate the loop/remove code in a function so that you can use it from any part of your code.
I have found the following tutorial on creating a selector engine..
http://blog.insicdesigns.com/2010/04/creating-your-own-selector-engine/
In javascript we have functions like
getElementById()
getElementsByTageName()
getElementsByName()
etc,.....But for the same functionality,in their selector engine,they are doing checks like
this.nodes[i].tagName == nm.toUpperCase()
instead of getElementsByTagName.What is the advantage of this approach?...
Also what is the usage of assigning all nodes to a vairiable using
e.getElementsByTagName('*');
There is an inconsistency when you get the tagName property of elements. Some browsers return uppercase and others lowercase. To normalize the output of the value, you have to do one or the other before continuing further operation.
As for e.getElementsByTagName('*');, i recently answered a question where the OP wants to find ALL elements containing an attribute name which has a prefix mce_. The only way to get such elements is to get all elements in the DOM, and inspect their attribute names.
There is also a good application of this getElementsByTagName('*') and that is determining the direct child of an element. For instance, in a very deep DOM. If I were to find certain parent elements based on an attribute and get it's children, normally you would do a recursive search from body downwards to find the parent. This would take a lot of recursive operations. Afterwards, you determine their children.
Another way to do it is to get all tags, determine their parent node, and if they have the parent with the attribute, they are the direct child. This method requires no recursion, only getElementsByTagName('*') and a loop through the nodeList that was returned.
this.nodes[i].tagName == nm.toUpperCase() is part of a method to filter the list of nodes by tag name.... so nothing to do with 'getting elements by their tag name'
the last point is not a real question.. you want to know reasons for "why would you select all nodes"? well you are writing a sector engine....
The following line
this.nodes[i].tagName == nm.toUpperCase()
Is within the function ofTag. It's filtering a set of nodes looking for nodes with the given name.
The next line
e.getElementsByTagName('*');
Retrieves all the children/descendants under a node so you can later filter it like the following
new DOMNodes(Selector.getAll(document)).ofTag('p').hasClass('note');