Retrieving an element by array index in jQuery vs the each() function - javascript

I was writing a "pluginable" function when I noticed the following behavior (tested in FF 3.5.9 with Firebug 1.5.3).
$.fn.computerMove = function () {
var board = $(this);
var emptySquares = board.find('div.clickable');
var randPosition = Math.floor(Math.random() * emptySquares.length);
emptySquares.each(function (index) {
if (index === randPosition) {
// logs a jQuery object
console.log($(this));
}
});
target = emptySquares[randPosition];
// logs a non-jQuery object
console.log(target);
// throws error: attr() not a function for target
board.placeMark({'position' : target.attr('id')});
}
I noticed the problem when the script threw an error at target.attr('id') (attr not a function). When I checked the log, I noticed that the output (in Firebug) for target was:
<div style="width: 97px; height: 97px;" class="square clickable" id="8"></div>
If I output $(target), or $(this) from the each() function, I get a nice jQuery object:
[ div#8.square ]
Now here comes my question: why does this happen, considering that find() seems to return an array of jQuery objects? Why do I have to do $() to target all over again?
[div#0.square, div#1.square, div#2.square, div#3.square, div#4.square, div#5.square, div#6.square, div#7.square, div#8.square]
Just a curiosity :).

.find() returns not an array of jQuery objects, but one jQuery object containing an array of DOM elements (a jQuery object, at it's core, is a wrapper around a DOM element array).
When you're iterating through, each element you're on is a DOM element. So, it needs to be wrapped in $(this) to become jQuery object and have access to those methods.
Also as a side note: The id attribute can't begin with a number, since it's invalid HTML you may or may not experience strange behavior, especially cross-browser (this rule applies for any invalid HTML).

No, the find method doesn't return an array of jQuery objects. You are creating a jQuery object for each element here:
console.log($(this));
If you log the value without creating a jQuery object from it:
console.log(this);
you will see that it's an element, not a jQuery object.
When you access the jQuery object as an array, you get an element. If you want a jQuery object you have to create one from the element.

Related

How to use StartsWith selector on a variable?

According to jQuery's API StartsWith selector is intended to be used on the entire document.
For example,
var $elements = $( "span[id^='MJXc']" );
will find all <span>s in the DOM that have IDs starting with 'MJXc'.
But what if I have an array of elements stored in a variable and I want to select only those elements that start with ... out of that array? Can I still use the StartsWith selector?
The following doesn't seem to work and gives out Uncaught SyntaxError: Unexpected token (
var $elements = $arrayofelements.( "span[id^='MJXc']" );
I did not add or remove any brackets, I just stuck a variable in front of the selector.
$arrayofelements looks like this in console:
0:span#MJXc-Node-7.mjx-mrow
1:span#MJXc-Node-28.mjx-mi
2:span.mjx-base
3:span#MJXc-Node-34.mjx-mi
Ideally, I would like to get elements 0, 1, and 3 reuturned, skipping element 2 as it doesn't have ID starting with 'MJXc'.
Use the .filter() method in JQuery.
$arrayOfElements.filter('span[id^=MJXc]');
Like most JQuery methods, it takes a selector. It returns a new JQuery object containing only the elements that matched the selector (in this case, a span with an ID starting with MJXc).
// get only the spans inside #parent div
$spansToFilter = $('#parent').children();
$filteredSpans = $spansToFilter.filter('[id^=MJXc]');
// prove we've filtered out the span with no matching ID
$filteredSpans.each(function(i, item) {
console.log(item);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="MJXc-Node-7.mjx-mrow">(external skip)</span>
<div id="parent">
<span id="MJXc-Node-7.mjx-mrow">A</span>
<span id="MJXc-Node-28.mjx-mi">B</span>
<span class=".mjx-base">(skip C)</span>
<span id="MJXc-Node-34.mjx-mi">D</span>
</div>
What you tried didn't work because in Javascript whatever.() would be invalid; You'd be trying to call a function with no name. In JQuery and javascript, you are always calling methods on the previous object in the chain obj.method(). Those methods are returning new JQuery objects which have the same set of methods, which is what allows the chaining to be possible. All the methods JQuery objects have are listed in the JQuery documentation, including .filter(), .find(), .children(), etc.
javascript specific answer:
from your $elements array, you can simply check whether the id of your element startsWith() a particular prefix or not. It it does, then you can simply push it into new array.
var $selectedElements = [];
for(var i=0; i<$elements.length; i++)
if($elements[i].id.startsWith("MJXc"))
$selectedElements.push($elements[i]);

jQuery throws an error that element.find() is not a function

I have written a small JS to iterate through a set of matched elements and perform some task on each of them.
Here is the code:
var eachProduct = $(".item");
eachProduct.each(function(index, element){
var eachProductContent = element.find(".product-meta").clone();
});
When I console log element it outputs properly and the exact objects. Why should jquery throw this error?
because element is a dom element not a jQuery object
var eachProductContent = $(element).find(".product-meta").clone();
Inside the each() handler you will get the dom element reference as the second parameter, not a jQuery object reference. So if you want to access any jQuery methods on the element then you need to get the elements jQuery wrapper object.
You are calling .find() on a plain JS object, But that function belongs to Jquery object
var eachProductContent = $(element).find(".product-meta").clone();
You can convert it to a jquery object by wrapping it inside $(). And in order to avoid this kind of discrepancies you can simply use $(this) reference instead of using other.
Use $(this) for current Element
var eachProductContent = $(this).find(".product-meta").clone();
you should change "element" to "this":
var eachProduct = $(".item");
eachProduct.each(function(index, element){
var eachProductContent = $(this).find(".product-meta").clone();
});

.children().innerHtml on a JQuery object from a DOM node object returns undefined

function getTaskProperties(node) {
var data = {};
data.name = $(node).children(".nameHere").innerHtml;
data.date = $(node).children(".dateHere").innerHtml;
data.class = $(node).children(".classhere").innerHtml;
console.log($(node).children(".nameHere")); // returns something like:
//[p.nameHere, prevObject: n.fn.init[1], context: div#entryTemplate.entry, jquery: "1.11.0", constructor: function, selector: ""…]
console.log($(node).children(".nameHere").innerHtml); //returns undefined
return data; }
function getAllTasks() {
var tasks = [];
$(".entry") .each(function (i, e) {
console.log (getTaskProperties(e));
})
for (var i; i<tasks.length; i++) {
console.log(tasks[i]);
}
}
This script runs through a series of HTML elements that look like the following:
<div class = "entry" id = "entryTemplate">
<a class = "trashButton"><i class="fa fa-trash-o"></i></a>
<p class = "classHere">History</p>
<p class = "dateHere">Due: Monday</p>
<p class = "nameHere">Graphic Organizer</p>
</div>
There are also a couple other elements that get included in the JQuery selector for <.entry>
My problem is that when I run $(node).children().innerHtml it returns undefined.
How can I properly get the value of .classHere, .nameHere, and .dateHere?
.innerHTML is a DOM property name (and you had it with the wrong capitalization).
$(node).children(".nameHere") produces a jQuery object.
.innerHTML is NOT a property of a jQuery object (it's a property of a DOM object) and thus is does not work on a jQuery object.
You can either use all jQuery:
$(node).children(".nameHere").html()
or you can fetch the DOM object from the jQuery object and then use .innerHTML as in:
$(node).children(".nameHere")[0].innerHTML
By way of explanation - a jQuery object and a DOM object are not the same thing. They are different types of objects that have different properties and methods.
A jQuery object contains an array of DOM objects (inside it). So, when you want to carry out an operation on the DOM objects, you can either use a jQuery method which will apply that method to the DOM objects inside the jQuery object or you can fetch the DOM objects out of the jQuery object and apply DOM methods/properties directly to the DOM objects.
Use .html() or .text()
$(node).children(".nameHere").html();
$(node).children(".nameHere") is jQuery Object you cannot directly use .innerHTML with it
You can do
$(node).children(".nameHere")[0].innerHTML;
or .get()
$(node).children(".nameHere").get(0).innerHTML;

Value is undefined when element is obtained with jQuery

Below is the code where I obtain my input element with jQuery:
var txt = $(tableRow).find('input:text');
if (txt.value == null) {
//TO DO code
}
and here's how I do it with pure JavaScript
var txt = document.getElementById('txtAge');
if (txt.value == null) {
//TO DO code
}
With the first way the value of the txt is undefined. But with the second way the value is what's inside the input element. Now more interesting is, on the bottom-right pane of the Mozilla Firebug if I scroll down to the "value" of the txt I can see it there, both ways.
I know I can simply say $(txt).val(), but I also want to understand why I can't access the value of an element if it's been selected by jQuery. Isn't jQuery just a library of JavaScript functions?
.value is not part of the jquery api. You should use .val() instead:
var txt = $(tableRow).find('input:text');
if (txt.val() == "") {
//TO DO code
}
A dom object and a jquery dom object are not exactly the same. In fact, you can open the Developer tools (in webkit) or Firebug (Firefox) to check what are they in the inside. Jquery holds more information (actually, it contains an instance of the dom that it's representing). So, if you wanted to use .value, you need to call the "generic" dom object from the jquery object, and then use .value.
jQuery selects DOM elements using various native and non-native techniques and places them all in it’s own array-like instance that also wraps them in their own API. jQuery doesn’t "extend" native DOM properties or methods, so you will need to target the DOM node to do that.
Think of it like this:
var node = document.getElementById('txtAge'); // the DOM node
var txt = $('#txtAge'); // the same node wrapped in a jQuery object/API
Since jQuery object holds an array-like collection of DOM nodes, so you can access the first element by doing:
txt[0] // same as node
But it’s generally recommended that you use the .get() method:
txt.get(0)
Another more jQuery-way to do what you want is to iterate through a jQuery collection using .each():
$(tableRow).find('input:text').each(function() {
// "this" in the each callback is the DOM node
if ( this.value == null ) {
// Do something
}
});
.find() will return an arry-like object. If you're sure that there's one, and one only, element matching your query, you could do
var txt = $(tableRow).find('input:text')[0].value;
That's not very jQuery-like, so to speak, more like a mismatch of both jQuery and DOM methods, but it'll get what you want. Also, since you show, as a DOM example, var txt = document.getElementById('txtAge');, this could be rewritten in jQuery as
var txt = $('#txtAge')[0];
var x = $(tableRow).find('input:text');
It's an jquery object .
`x.value`
There is no property value in jquery object . So it returns undefined.
x.val() is a method you can use for get the value of an element.

What object does jquery return exactly?

I've been working on my own personal JavaScript library for a while now, and it works fine. But I've been wondering about the jQuery return object.
Lets say you have a few divs in your DOM and you select them with $("div") jquery actually returns the selected nodes (as an object/array?) in the console log and you can mouse-over them to see where they are in the documents.
My object actually returns the entire object itself, so if you call kj("div") (Where kj is my object name) it shows up like this in the console log:
> kj
> elements: Array[10]
> length : 10
> more stuff
My question is, how can I make it return something like jQuery?
Thanks in advance.
I think what you are looking for is that in jQuery the Array of elements is the primary object, the methods and other information is connected to that array as properties.
function $$(tagname){
var x = document.getElementsByTagName( tagname );
x.moreStuff = true;
return x;
}
var d = $$('div');
because typeof Array === 'object' you can arbitrarily attach methods and properties to an array.
JQuery hooks up it's own references to an object whick in turn reference to things in the dom. Those references are a little more complex than just the "contents of the html" as there are events attached. JQuery also has very efficient "Selectors" that iterate over the dom and build those references.
I have to say I agree with the Scrum Meister. JQuery's an accepted standard across even Microsoft development these days (WOOHOO!). Why not use it?
Open you console on this page and do console.log($('#custom-header')) and you will get the result. I think that, jquery will return an object with following methods and property which we use on them like hide() and show(). I think it is better to use jquery then to create another library.
>>> console.log($('#custom-header'))
[div#custom-header]
0
div#custom-header
context
Document what-is-the-jquery-returned-object-exactly
jquery
"1.4.4"
length
1
selector
"#custom-header"
init
function()
TextAreaResizer
function()
_toggle
function()
add
function()
addClass
function()
addSpinner
function()
addSpinnerAfter
function()
after
function()
ajaxComplete
function()
ajaxError
function()
ajaxSend
function()
ajaxStart
function()
ajaxStop
function()
.......
.......
.......

Categories

Resources