.each(function{} .split and .attr - javascript

I recently came across these codes while learning how to program an animated gallery and have no idea what they mean:
var items = $('#gallery li'),
itemsByTags = {};
items.each(function(i){
var elem = $(this),
tags = elem.data('tags').split(',');
//Add data attribute for quicksand
elem.attr('data-id',i);
I know that the var items = $('#gallery li'),itemsByTags = {};means that I am grabbing the list ID through jQuery and then setting a variable named itemsByTagsto an empty string.
After which items.each is a loop that is design to run through all the lists. But i have no idea what is function(i)? Why is there an i inside the function? What is this ithing?
Also, what does $(this) mean? Does it refer to the items?
Lastly, what does the .attr() mean with the i inside?

Just as a warning, questions like this one aren't very highly regarded on Stack Overflow because they can be answered by visiting a single page about the function you're using, which in this case would be the documentation for the jQuery .each() function. Questions like this one are often downvoted and never get an answer, so before posting a question, you should always check the documentation for the code or libraries that you are using to see if your question may already be answered there.
With that out of the way, here are a couple of points that should help answer your questions:
itemsByTags = {}; sets the variable to an empty object, not a string. This variable is not used in the code you provided, though, so it's not very relevant to the question at hand.
items.each(function(i){ is, as you noted, a function designed to loop through an array of items. Each functions normally output two different values, a key and a value. In this case, however, only one variable is supplied in the function call, and so the function will only receive the first value, which is key. The key is the 0-based index of the number of the item you are on. This number will increase by 1 each time you move to the next item in an array. A different way of explaining this would be to say that array[key] would return the value in array at item number key.
$(this) is jQuery's way of referring to the object currently being retrieved from the array. Because var items = $('#gallery li') retrieves a list of all of the objects in the page that match the selector #gallery li, $(this) refers to the actual object in the page whose array element is being retrieved. $(this) can be modified and acted on in the same way as if you targeted it using a normal selector like $('#gallery li').eq(i).
You may have determined by now exactly what the last line is doing. $(this).attr('data-id',i); finds the current array item's element in the page and sets its data-id attribute to its 0-based index relative to its siblings. If you iterate through the array in this way, the 6th (just for example) $('#gallery li') element's data-id attribute would be changed to 5.
Hope this is helpful!

Related

How to treat the return value of jQuery functions that return a bunch of elements

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().

jQuery Id Selection and Dynamic Arrays

I have some code I'm struggling with. The good news is the code working as intended for a single instance; after some thought I've decided to feature multiple of these image selectors on a page. This works but the ugly approach of duplicating the code doesn't scale well (e.g. what if you want 50 of these on there?) The snag I've hit is how I can refer to a specific array. Is an array even an ideal solution for this?
The Objective
I have a series of images that a user may select from, up to X amount. The selected image ids are stored in an array and the image is added to a "selected images pool". This occurs by using an onClick for the slider, I obtain the Id from the element attributes. This is where I'm getting stuck.
var dataArray = $(this).closest("[id^=carousel]").data('array');
var slideCounter = $(this).closest("[id^=carousel]").data('counter');
slideCounter = dataArray.length;
The slideCounter returns the length of the string, not the array elements. How can I tell this code to refer to a particular array? See the fiddle for a better idea of the markup and code: jsFiddle
I have no doubt that there is a better approach. I'm relatively new to front end work, I'd appreciate any insights, I've burnt some brain cells on this, thanks!
From looking at your HTML, it looks like when you do this:
var dataArray = $(this).closest("[id^=carousel]").data('array');
what you're trying to do is to read the name of an array with .data() and then somehow turn that name (which is a string) into the array that's in your variable. My guess is that there's probably a better way to structure your code rather than putting javascript variable names in your HTML. I'd probably put a key name in the HTML and then store the arrays in an object where you can access them by that key name at any time.
Without trying to refactor your code, here's an idea for what you were trying to accomplish:
If selectedSlidesIdArray1 is a global variable, then you can do this:
var dataArray = window[$(this).closest("[id^=carousel]").data('array')];
Using the [stringVariable] notation on an object, lets you access a property by a literal string or a variable that contains a string. Since all global variables are also properties on the window object, you can do it this way for global variables.
If selectedSlidesIdArray1 is not a global variable, then you should probably put it in an object and then you can do this:
var dataArray = yourObj[$(this).closest("[id^=carousel]").data('array')];
Instead of trying to translate an arbitrary string into a JavaScript variable of the same name, why not just use another array? You can have nested arrays, which is to say an array of arrays.
Thus, instead of selectedSlidesIdArray1, selectedSlidesIdArray2, etc., you would have one selectedSlidesIdArray with sub-arrays, which you could then pull the index for using a data attribute.

Remove all the DOM elements with a specific tag name in Javascript

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.

Why does .splice always delete the last element?

In the javascript, there are two arrays:tags[] and tags_java[]. I use .splice to delete certain items, which of the same index in the two arrays. The tags[] works fine, but tags_java doesn't, it seems always delete the last item.
Here is the code and the jsfiddle link.
var tag = $(this).text();
var index = $.inArray(tag, tags);
tags.splice(index,1);
tags_java.splice(index,1);
Nah, both don't work, because you're not actually finding the correct index of your tag.
Why not? Because $(this).text() includes the delete mark you added, Ă— - e.g. "MorningĂ—". Since that's not in your tags array, index will be -1. tags.splice(-1, 1); will remove 1 item from the end of the array.
In general, it's never a good idea to use presentation text (i.e. the text of your tag element) as data (e.g. using that text as a lookup value in an array). It's very likely that it'll be broken when something changes in the presentation - like here. So a suggestion would be to store the data (what you need to look up the tags) as data - e.g. using the jQuery-provided data() API - even if it seems redundant.
Here's a quick example - just adding/replacing two lines, which I've marked with comments starting with "JT": JSFiddle
Now, instead of looking up by $(this).text(), we're looking up by the data value "tagValue" stored with $(this).data() - that way, the lookup value is still bound to the element, but we're not relying on presentation text.
If the tag is not in the tags array, $.inArray will return -1, which would then cause the last item to be deleted.
You have to make sure that the item is actually in the array.

Call show on array of jQuery objects

I have a little problem concerning performance of jQuery.show.
This problem occurs in IE8 (probably also versions below, but IE8 is of my interest).
I have an array of jQuery objects, lets call it elements.
I want to show them, so i did:
for (var i = elements.length - 1; i >= 0; i--) {
elements[i].show();
}
The bottleneck seems to be the call to show. The array is already generated, so that takes no time. looping through an array should not be a problem either.
I thought of reducing this to one call to show by creating a new jQuery element containing all my elements. but I was not sure how to do this. I tried by jQuery.add.
var $elements = elements[0];
for (var i = elements.length - 1; i >= 1; i--) {
$elements = $elements.add(elements[i]);
}
$elements.show();
Now, this time it seems to be a problem with jQuery.add. Probably because it always creates a new object.
So, I thought of three different approaches that could solve my problem. Maybe you can help me with one of them:
Is there a jQuery method like add that does not return a new object, but instead adds it to the current jQuery element?
Is there an easy and fast way to create a jQuery element by an array of jQuery elements?
Is there a way to show all jQuery objects in an array in a faster way?
Answering just one of the question would probably help me out here. My problem is, that jquery always expects an array of DOM elements and not an array of jQuery elements in its methods.
Thanks a lot in advance!
-- EDIT about the contents of elements
I have a jstree that dynamically creates nodes (that is, li elements). These elements have an attribute data-id to identify them.
Now, I could always query for something like $('li[data-id=xxx]'), but this would be very slow. So instead, when li elements are created, i cache them into a dictionary like object (key is the data-id, value is the node). Out of this object, i generate my array elements. This happens very fast.
The array can have a size of up to 4000 nodes. Every jQuery Element in the array only contains one DOM-Element (li).
Edit
After reading your update, and the comments, this Very small one-liner is most likely going to be the answer:
elements.each($.fn.show);
Using the jQ each method to apply (well, internally: call is used) the show method to all elements.
The easiest, and fastest way to create a jQuery object from an array of jQuery objects would be this:
var objFromArr = $(jQarr);
I've just tested this in the console:
objFromArr = jQuery([jQuery('#wmd-input'),jQuery('#wmd-button-bar')]);
objFromArr.each(function()
{
console.log(this);//logs a jQ object
console.log(this[0]);//logs the DOMElement
});
But having said that: you say elements is an array of jQ objects, but if it's the return value of a selector ($('.someClass')) then really, it isn't: in that case, your loop is "broken":
elements = $('.someClass');
for (var i=0;i<elements.length;i++)
{
console.log(elements[i]);//logs a DOMElement, not a jQuery object
}
//It's the same as doing:
console.log(elements[0]);
//or even:
console.log($('.someClass').get(0));
But in the end, if you have an array of jQuery objects, and you want to invoke the show method on each and every one of them, I suspect this is the best take:
elements.each($.fn.show);//use the show method as callback

Categories

Resources