in jQuery function:
.on(event, [selector,] [data,] handler)
How jQuery parse this call:
on('click', 'tag3', () => {})
tag3 is selector or data?
The last argument must be the handler. So if there are two arguments there there is no data and no selector.
If there are four arguments than the second one must be selector and the third one must be data.
So it only becomes tricky if there are exactly three arguments.
If the second argument isn't a string, then it can't be a selector, so it must be data.
If it is a string then it could be a selector or data. Now jQuery could do some heuristics by running it through the selector engine and seeing if it is a valid selector … but it doesn't. It just assumes that if the second argument is a string then it is a selector.
How jQuery distinguish between 'data' and 'selector' parameter?
They have a different data-types
data - is a plain object (not a DOM or jquery object)
selector - is a string or a jquery/DOM/DOM-array object.
so, jquery can make out whether an argument is a selector or data by judging the properties of the argument, for example this and this
return obj instanceof HTMLElement; //to check if it is a DOM object
or
return obj instanceof jQuery; //to check if it is a jquery object
tag3 is selector or data?
As per documentation
If a string is passed as the parameter to $(), jQuery examines the
string to see if it looks like HTML (i.e., it starts with ).
If not, the string is interpreted as a selector expression, as
explained above. But if the string appears to be an HTML snippet,
jQuery attempts to create new DOM elements as described by the HTML.
Then a jQuery object is created and returned that refers to these
elements.
If the string passed to jquery method is an HTML then subsequent object is either a document (DOM object) or an attributes object.
Related
When accessing an array, when is it appropriate to use the .eq() function?
For example, I have...
slides.eq(slidesLength-1).css("z-index", (slidesLength-1));
and later I have...
for(i=0; i<slidesLength-1; i++) {
$(slides[i]).css("left", "-100%");
}
In the first piece of code, the slideshow stops functioning if I don's use the .eq() function. However, the second piece seems to function whether I use the .eq() function or not. Why is this?
slides is not an array. It's a jQuery object. The .eq() method returns you the element at the specified index as a jQuery object.
While jQuery objects may not be arrays, they can pretend to be by having a length property as well as properties corresponding to the indexes. (Since they are not arrays, you can't call methods like .pop(), .forEach(), etc. on them.)
When you do slides[i], you are actually getting the DOM element, not a jQuery object. The $() function turns the DOM element into a jQuery object.
So, when you do slides.eq(1), internally jQuery is doing $(slides[i]).
P.S. Objects, like jQuery objects, that pretend to be arrays are called "array-like objects". If you console.log(slides), it may look like an array. This is just your console trying to make things convenient for you. (See this question for more info: Creating array-like objects in JavaScript)
.eq() is a jQuery method which returns a jQuery object, while accessing by index returns plain DOM element. You should use eq() when you want to use jQuery methods (css() in this case) on the returned selection.
The reason $(slides[i]) works is because you're constructing a jQuery object by passing the plain element to $() constructor.
Your slides variable is not an Array, but a jQuery object.
.eq() returns a jQuery object, eventually empty if index is out of bounds, and a negative index is counted from the end.
.get() returns a DOM Element, or undefined if index is out of bounds, and a negative index is counted from the end.
[] returns a DOM Element, or throw an Error if index is out of bounds.
...
Additionally, jQuery methods let you interact with a set of elements as it was alone. So you if you do:
slides.css("left", "-100%");
It is applied on every matched elements contained in the jQuery object. It is unnecessary to loop over them.
...
Also the preferred way to loop over matched elements is using the each() method:
slides.each(function (i, el) {
var $el = $(el);
});
...
Also it is an established convention to prefix jQuery variables with a $ sign; it let you to easily differentiate DOM elements from jQuery objects. But that's only a matter of taste.
Say I have a map on an array of elements. The callback function takes the index and the value at that position in the array.
If I wrap the array element that the callback receives in $(), it behaves as I expect. If I use it without wrapping it in $(), it gives an error.
var nonHiddenElements = $( "form :input" ).not(':hidden');
nonHiddenElements.map(function(index, element){
input_id = $(element).attr('id'); // this works
input_id = element.attr('id') ; // this gives an error
})
Can someone explain how this works.
Is this a jQuery quirk, or a JavScript thing?
What type of objects does my nonHiddenElements array contain exactly?
What is element that gets passed to the callback?
And mainly what is the $() doing?
You need to understand how jQuery actually works. I will try to explain it briefly.
$ is nothing but a normal javascript function. jQuery === $, is just a function with a fancy name. This function does a lot of different things, depending on what you pass in it. For example if you pass a string it will be treated as CSS selector and jQuery internals will try to find corresponding DOM elements. Or if you pass a string starting with < and ending with > jQuery will create a new DOM element by provided HTML string.
Now if you pass a DOM element or NodeCollection of DOM elements, it/they will be wrapped into jQuery instances so that they can have a jQuery prototype methods. There are many prototype methods jQuery offers. For example text, css, append, attr - those are all methods of jQuery prototype. They are defined basically like this (simplified):
jQuery.prototype.text = function() { ... }
Normal DOM elements don't have those convenient methods jQuery provides. And inside of methods like map or each if you check this value or element parameter like you do, you will see that they are actually not jQuery instances:
element instanceof jQuery // => false
and of course you can't use instance methods with not an instance.
So in order to use jQuery prototype methods you need have a jQuery instance, which you can obtain if you call jQuery function with DOM element passed in it:
$(element) instanceof jQuery // true
Javascript is a programming language.
jQuery is a JavaScript Library.
With jQuery:
$("some element")
In native JavaScript you would have to do something like this.
getElementById('elementByID')
Explained in detail here: https://developer.mozilla.org/en-US/docs/Web/API/document.getElementById
MDN is a great resource for beginners. https://developer.mozilla.org/en-US/docs/Web/JavaScript
If I'm creating elements like:
var someLink = $("<a/>", {
className: "some-class",
href: "some-path",
id: "some-id",
etc...
});
Where in the jQuery docs can I find what is valid, and what to call this format in the first place? Obviously, this is helpful so I know not to try class: but to use className: instead. Is href: even valid, etc? Those kinds of things might be helpful to know.
You can check official jQuery documentation about this function jQuery( html [, ownerDocument ] ), check the Important section at the end, which describes what you can use as a second parameter for this function.
As of jQuery 1.4, the second argument to jQuery() can accept a plain
object consisting of a superset of the properties that can be passed
to the .attr() method.
Important: If the second argument is passed, the HTML string in the
first argument must represent a a simple element with no attributes.
As of jQuery 1.4, any event type can be passed in, and the following
jQuery methods can be called: val, css, html, text, data, width,
height, or offset.
As of jQuery 1.8, any jQuery instance method (a method of jQuery.fn)
can be used as a property of the object passed to the second
parameter.
I'm writing a general purpose helper function in JavaScript. It accesses the className property of the element.
But since I'm using jQuery, it turns out that sometimes the element passed as an argument is actually an array (a jQuery set).
What is the simplest way to use an argument if it's an element or get the first element from the set if the argument is a set? Does jQuery have a tool for this?
You can test if the object is a jQuery object by using instanceof:
if (myObject instanceof jQuery) {
// use $.each to loop over myObject and get class names of all
// or just use myObject[0].className to return only the first
} else {
// it's not a jQuery object
}
You always want a native element? Each jQuery object has a property jquery (containing the jQuery version) so you can use it to check if the element you got is likely to be a jQuery object:
obj = obj.jquery ? obj[0] : obj;
If you are not into ducktyping:
obj = (obj instanceof jQuery) ? obj[0] : obj;
In case you want to pass a single element, an array of elements or a jQuery object to the same method, do the following:
function stuff(element) {
element = [].concat(element)[0];
}
If you have to deal with both jQuery objects and non-jQuery elements, this is a bit tougher. Keep in mind that the jQuery collection can possibly have different classNames for each element, i.e. the first and others may not be the same.
It's slightly inefficient, but this will work:
function (obj) {
var className = $(obj).get(0).className;
}
Wrapping a jQuery object in jQuery() does nothing, but wrapping the element allows you to access it again via .get. It's inefficient because you may have an extra $() call.
If that's no good, you could check obj.hasOwnProperty('className') since a jQuery object usually should not have it, but I think that is riskier.
Is a jQuery Object an Element or an Array of Elements?
Strictly, neither.
A jQuery object is a Javascript object that has some of the Array capabilities. In most aspects you can use it as an array of elements.
If the jQuery object may contain several elements, and you only want the first, you can use the first method to get that:
elements = elements.first();
If the parameter can be either an element, an array of elements, or a jQuery object, you can wrap it in a jQuery object to handle all the cases:
elements = $(elements).first();
How come the equation in the title is false? How do check if two jQuery selectors point to the same DOM object?
You are comparing two distinct jQuery objects because you call $() twice (once for each side of the equation), and as MooGoo explains jQuery creates new wrapper objects for each time you call it. That's why the comparison ends up returning false.
You can extract a DOM object from each jQuery object by either using get() or array dereferencing, then compare these elements. The following both return true because both identical selectors match the same body DOM element:
$('body').get(0) == $('body').get(0)
$('body')[0] == $('body')[0]
If you want to test against a jQuery selector, use is(). Note that, unless your selectors are identical, the selectors you use may not necessarily match the same DOM elements (it's still better to use the above). This also returns true:
$('body').is('body')
Because jQuery creates a new wrapper object for each $ call, and in Javascript all objects are distinct, even if they have the exact same properties/methods.
On the other hand, document.body == document.body would evaluate to true.
Use $.is()
http://api.jquery.com/is/
Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments...
Unlike other filtering methods, .is() does not create a new jQuery object. Instead, it allows you to test the contents of a jQuery object without modification. This is often useful inside callbacks, such as event handlers...