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
Related
i have a div, with 3 tables in it.
var x = tempDiv.getElementsByClassName("hiscore_table");
I know this for sure because when i console log it, it prints like this:
I make a new div to append the tables on
var newDiv = document.createElement('div');
for (let i = 0; i < x.length; i++) {
newDiv.appendChild(x[i]);
}
I then append to the body, but only 2 tables show. I debugged the for loop and its only running the loop 2 times. If i print x.length i get 3. Im not too good at debugging but when i append child it seems to be deleting it from the old div, maybe thats the cause.
You’re creating a new <div> and appending elements that currently exist in the DOM to it. This means that you’re removing those elements from the DOM in order to append them to the <div> (which is not in the DOM).
Next, the thing you need to know about HTMLCollections (the return value of document.getElementsByClassName) is that they’re a live list. This means that any changes to the DOM are immediately reflected in the collection.
So, i is 0, you append the first element, your collection now only contains two elements.
Next, i is 1, you append the second element of your remaining collection, which is the third element overall. Only one element remains in the collection.
Next, i is 2, which is out of bounds for your now-one-element collection.
This is similar to removing items from an HTMLCollection.
There are a few approaches to solve this, like iterating in reverse order. But I prefer a functional approach:
Array.from(x).forEach((table) => newDiv.appendChild(table));
This converts the HTMLCollection to an array right away, so it’s no longer a live list.
Just for completeness, if you want to support older browsers without the need for pollyfills or similar (i.e. write robust, easily maintained code), you can use a while loop:
while (x[0]) {
newDiv.appendChild(x[0]);
}
Oh, another simple fix is to use querySelectorAll, which returns a static NodeList:
var x = tempDiv.querySelectorAll(".hiscore_table").
i was adding many dom objects (svgg elements) around 3000 to an empty jquery set using .add() jquery method but it takes a lot of time and the ui freezes when the javascript is running.And i found out that add every time sorts the set which is taking a lot of time but why is there a need of sorting.
here is the javascript code.
var list= $jquery();
for(x=0;x<no_of_objects(around 3k+ in my case);x++){
list.add(items[x]);
}
Let's see what jQuery docs say about .add() method:
When all elements are members of the same document, the resulting collection from .add() will be sorted in document order; that is, in order of each element's appearance in the document. If the collection consists of elements from different documents or ones not in any document, the sort order is undefined. To create a jQuery object with elements in a well-defined order and without sorting overhead, use the $(array_of_DOM_elements) signature.
https://api.jquery.com/add/
So if you want to preserve the order, try $(items) as they suggest..?
Because jQuerys add() does not only append a value to a set, it actually creates a new sorted collection and then adds the value to it..
For more info, take a look at the docs: https://api.jquery.com/add/
You can add this elements in loop to element not attached to DOM, and then attach them in one move. Each time you modify DOM, browser must recalculate view.
var list = new Array();
for(x=0;x<no_of_objects(around 3k+ in my case);x++){
list.add(items[x]);
}
$('#list').append(list.join(""));
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.
The Problem
I need some properties of each item that query returns as array of objects
What we do right now
$('selector').each(create array of texts or whatsoever);
What is wrong?
Why should we iterate over elements for each requirement?
Here is the same thing in LINQ
IQueryable<Book>;
books.Select(b=> b.Text).ToArray();
// or another sample
books.Select(b=> new { b.Text , b.ISBN}).ToArray();
What do we/i need?
Selecting specified element properties as array of objects without reiterating over elements - something that called deferred enumeration
Is it possible?
I think yes it is, because right now i have some ideas.
I already know about 'map' and 'each' methods, beware that both of them will reiterate over selector items.So yes map will results what i want, but not exactly.
Also note that even C# that have more better performance than java-script is using this method that i'm asking for,
So this is a requirement for all web-developers not just me and that's exactly why i'm sharing the problem here to be solved.
Research result
Iteration over elements using jQuery is inevitable because jQuery itself is not finding elements using loop over document elements until that's necessary for example pseudo classes, so for implementing deferred enumeration over jQuery infrastructure we have to force jQuery to iterate over items, and that makes it slow.
I'd implemented deferred enumeration using a pseudo class named 'select' and passing in .net like lambda expression.That was handling selects very nicely just like .net, but result was slower than map and each jQuery methods up to 50%.Finally the answer is jQuery map method.
You might be looking for the map() method:
var books_text = $(".book").map(function() {
return $(this).text();
}).get();
var books_info = $(".book").map(function() {
var $this = $(this);
return {
text: $this.text(),
isbn: $this.attr("isbn") // If stored in an attribute.
};
}).get();