Iterating through a jQuery object array - javascript

I know this has been asked and answered a couple times already, but I'm still confused about how to reference the current object when iterating over a jQuery array. For example, the following code gives me the error TypeError: genH3Array[i].next is not a function. What is the right way to reference the current array object?
var genH3Array = $('#Generation_II').parent();
genH3Array.push($('#Generation_III').parent());;
genH3Array.push($('#Generation_IV').parent())
$.each(genH3Array, function(i, value)
{
if(genH3Array[i].next().attr("align") == "center")
{ genH3Array[i].next().next().next().insertBefore(heading.next())
}
genH3Array[i].next().next().insertBefore(heading.next())
genH3Array[i].next().insertBefore(heading.next())
})
EDIT: Thanks for all your help, everyone. I know this was probably a cinch for most of you, but it was a major headache for me. The corrected code is below:
var genH3Array = $('#Generation_II,#Generation_III,#Generation_IV').parent();
$.each(genH3Array, function(i, value)
{
console.log($(this).next());
if($(this).next().attr("align") == "center")
{
$(this).next().next().next().insertBefore(pokemonHeader.next())
}
$(this).next().next().insertBefore(pokemonHeader.next())
$(this).next().insertBefore(pokemonHeader.next())
$(this).insertBefore(pokemonHeader.next())
})

This part:
var genH3Array = $('#Generation_II').parent();
genH3Array.push($('#Generation_III').parent());
genH3Array.push($('#Generation_IV').parent());
...isn't really the way to use .push() against a jQuery object. When you .push() a value in, it should be a DOM element. Not a jQuery object.
You could simplify that entire bit like this:
var genH3Array = $('#Generation_II,#Generation_III,#Generation_IV').parent();
Now you'll have the .parent() of all three in the object.
Not entirely sure what the each is supposed to do, but it seems like you're trying to take the next three elements of each one, and insert them after some heading element.
$.each(genH3Array, function(i, value) {
if($(this).next().attr("align") == "center") {
heading.after( $(this).nextUntil('sometarget:last') );
}
heading.after( $(this).nextUntil('sometarget') );
});
I really don't know if this is what you want. It's a little hard to tell.

Both value and this point to the current item in the iteration, but that isn't your problem. Your problem is that the item returned by [] on a jQuery object isn't a jQuery object. You could do this:
$(genH3Array[i]).next()

Adding to what #patrick dw said: once you get the right selector, you can use the following syntax:
var getH3Array = ('#Generation_II,#Generation_III,#Generation_IV').parent().each(function() {
$(this); // this references the dom element matched, so:
if($(this).next().attr("align") == "center") {
// do something here
}
});

I think what you want is
var array = $("#c1, #c2, #c3").parent();
$.each(array, function(){
console.log($(this).next());
});
In $.each callback, the this variable point to the current element. If you are iterating through a jquery array like what you have, it will be iterating through the dom elements not jQuery objects, so you need to get the jQuery objects corresponding to them by using $(this).
jQuery.each

Related

Slicing an object off of a jQuery collection [duplicate]

In Javascript, arrays should have methods pop and shift.
However, JQuery objects seem to be missing these methods:
$('div').shift(); // Error, shift is undefined
$('div').pop(); // Error, pop is undefined
$('div').splice(); // Splice is OK actually
I wonder why these functions are missing - after all, the jquery object is just an array.
What's the easiest way of performing pop and shift functions on jquery objects?
They're missing because a jQuery object isn't an Array.
(function( $ ) {
$.fn.pop = function() {
var top = this.get(-1);
this.splice(this.length-1,1);
return top;
};
$.fn.shift = function() {
var bottom = this.get(0);
this.splice(0,1);
return bottom;
};
})( jQuery );
EDIT: .slice() doesn't modify the original object. Fixed to use .splice() instead.
Your safest bet would be to just use:
[].pop.call($('div'))
[].shift.call($('div'))
If you want to use the exact syntax in your example you can augment jQuery.fn:
jQuery.fn.pop = [].pop;
jQuery.fn.shift = [].shift;
The latter works well for the mutator methods. It'll work for the accessor and iteration methods too, but be advised that many of those returns a pure array that you'd have to rewrap. Be aware that jQuery has is own version of some of these (e.g. .map, .slice, .filter, etc.) that you probably don't want to overwrite.
This seemed to work for me:
var divArray = $('div').toArray();
var elem = $( divArray.shift() );
.toArray() return the DOM elements as a JavaScript Array, which can be used as intended. Then all you need to do is convert it back into a jQuery object.
I realize this answer has already been selected, but here's another alternative that isn't too hard to remember, in case you don't want to worry about having to install plugins all the time.
$('div > :first').detach(); // shift
$('div > :last').detach(); // pop
By the way, I realize there are performance issues with using :last selector as part of your primary selector so you may want to consider doing something like this for pop:
$('div').children(':last').detach();
var $firstDiv = $( $('div').splice(0, 1) );
Another way using jQuery 1.9.1+:
$('div').first().remove();
$('div').last().remove();

Does removing elements from within jQuery.each mess up the loop?

Let's say I do something like :
$('.item').each(function (index)
{
if (index === 3)$(this).remove();
else if (index === 4)$(this).remove();
});
Will this work or will I mess up the loop/indexes since I will be removing elements from an array while looping through it ?
Same question when adding :
$('.item').each(function (index)
{
$(this).parent().append('<div class="item"></div>');
});
Will this create an infinite loop?
Not it doesn't as you are removing the element only from the dom structure not from the jQuery object itself.
The jQuery obejct is not a live object like the HTMLCollection object returned by getElementsByClassName().
So even though the element is removed from the dom, its reference is still present in the jQuery object which called the each method.

jQuery compare two DOM object?

Clicking on an element:
$('.my_list').click(function(){
var selected_object = $(this);
$('.my_list').each(function(){
var current_object = $(this);
if( selected_object == current_object ) alert('FOUND IT !');
});
});
I don't know why, but I don't get the alert message "FOUND IT !".
You can use the jQuery.is function:
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.
if (selected_object.is(current_object)) {
...
}
An alternate solution is to use jQuery.get function to get the raw elements and compare them using == or === operator:
if (selected_object.get(0) == current_object.get(0)) {
...
}
jsFiddle demo
There's good answer provided... but it's important to understand, why you directly can't compare selectors in jQuery.
jQuery selectors return data structures which will never be equal in the sense of reference equality. So the only way to figure this out is to get DOM reference from the jQuery object and to compare DOM elements.
The simplest comparison of DOM reference for the above example would be:
selected_object.[0] == current_object.[0]

Determine # of items in jQuery array and loop through them?

I have an AJAX script that receives a string from a mySQL query returned by PHP.
This string is then parsed and put into an array in Jquery and the results are printed to the screen using .html()
The length of this array varies from 0 items to many, how would I count the items in the array then loop through and print them to the screen.
Here is my UPDATED code per the advice below, though I am still not sure if the for loop goes inside the .html() function or outside?
UPDATED CODE TO INCLUDE .each()
UPDATE 2: Replace (this) in the .html() function with the element I want the text written in and it is working partially, issue is now it is only printing the last item in the array?
UPDATE 3: Seems you can only have a single .html() function run, for instance if I add another .html() statement under the one that is returning the last item in my array it will only now echo on the screen the test value.
$("#n_detail").html(partsArray[index]+"<br />").addClass('jText').fadeTo(900,1);
$("#n_detail").html("Test").addClass('jText').fadeTo(900,1);
It will only print "Test", not the last item in the array like it was previously?
<script type="text/javascript">
$(document).ready(function() {
$("#primary").change(function()
{
$.post("lib/ajax_load_job_detail.php",{ _primaryid_n:$(this).val() } ,function(data)
{
var string = data;
var partsArray = string.split('|');
$("#n_detail").fadeTo(200,0.1,function() //start fading the messagebox
{
$.each(partsArray, function(index) {
$("#n_detail").html(partsArray[index]+"<br />").addClass('jText').fadeTo(900,1);
});
});
});
});
});
Sample value of array partsArray[0]12/12/2005, partsArray[1]This is a sample note from December, etc...
partsArray.length
will give you the items in the array. You can loop either with
for(var i=0;i<partsArray.length;i++){
or using the jquery addon
$.forEach
If you are iterating through an array then you could use the jQuery function each().
Here's a link to the docs: http://api.jquery.com/jQuery.each/
Here's a sample from the docs using your array:
$.each(partsArray, function(index, value) {
alert(index + ': ' + value);
});
EDIT - based on a comment the OP added to another answer, here's a better example using the OPs code:
$.each(partsArray, function(index, value) {
value.addClass('jText').fadeTo(900,1);
});
EDIT 2 - you need the part of the code that is per element of the arry inside the loop and based on your edits I think it should look like this:
$.each(partsArray, function(index) {
$(this).append(partsArray[index]+"br />").addClass('jText').fadeTo(900,1);
}
Cheers,
James
Here is a typical loop structure:
var partsArray = string.split('|');
for(var x=0;x<partsArray.length;x++) {
//...your code ...
//x is the index., so partsArray[x] is the current element
}
Use for ... in, it's significantly faster than jQuery's $.each method, and isn't much different - it provides you with the index of the item in i, rather than the value.
for (var i in partsArray)
{
// You can access values via...
console.log( partsArray[i] );
// Alternatively, this will make it an exact clone of $.each
var value = partsArray[i];
console.log( value );
}

jQuery set call back on child elements

I am trying to attach an onChange callback to all the input elements under the div #dim. It selects all 3 input elements, but returns an exception:
Uncaught TypeError: Object 0 has no method 'change'
It may be because x may not be a jQuery object. How would I make this work?
function registercb() {
var sel = $("div.dim > input");
for (x in sel) {
x.change(function() {
dosomething();
});
}
}
You can simply do:
function registercb() {
$("div.dim > input").change(dosomething);
}
A few things to watch for:
Inside that iteration (don't use this, see the next point) x is the DOM element, not a jQuery object which has the .change() method, you would need to wrap it in a jQuery object like $(x), but again that isn't the correct solution here.
Don't use a for(...in...) loop to iterate an object (a jQuery object is array-like), that type of loop is for enumeration.
Most jQuery functions (almost all) run on more than one element, so just run it on the set to affect all elements, .change() is one of these.
In the cases you do need to loop, check out .each(), as it'll make your life much easier, don't use this here, it's only an example of what it would look like:
Example:
function registercb() {
$("div.dim > input").each(function() {
$(this).change(dosomething);
});
}
You don't have to loop over the elements. You can think of a jQuery object as holding a collection. When you do:
var sel = $("div.dim > input");
It means that sel has all the input elements in it, so then when you run a method like change() it will affect all of the elements in the collection. Thus you can do something like this:
function registercb() {
$("div.dim > input").change(function(){
dosomething();
});
}
Bonus knowledge: Now your problem is that when you were doing for( x in sel ) you are getting a lot of stuff on the jQuery object itself that you don't want. If you run the following code in chrome you'll see it outputting a lot unexpected stuff:
for( x in sel ){
console.log( x );
}
Instead jQuery has the each that lets you loop over the things you want:
sel.each(function(index, item){
console.log(item);
});
You can even use it on other things, which is really handy!
$([1,2,3]).each(function( index item ){
console.log( item ); // 1,2,3
})
Assuming your 'dim' div has an ID rather than a class of dim, you can simply do this:
$("#dim > input").change(function() { dosomething(); });
Working example.
In the text you refer to #dim whereas in the code you're refering to .dim - # selects by ID and . selects by class, so if your div is in the format <div id="dim"> then you won't find any matched elements with div.dim as your selector.

Categories

Resources