The following command
document.querySelectorAll('#divConfirm table')[1].querySelectorAll('tr')
gives a node list with 3 tablerow (tr) elements in it. If I know the list size, I can access the last element via.item(2).
Is there a way to get the last element directly without resorting to .length first?
There's at least one way
var els = document.querySelectorAll('#divConfirm table')[1].querySelectorAll('tr');
var last = [].slice.call(els).pop();
but, the following statement
But if I do not know the length prior to running the script
makes no sense, you already have the collection of elements, so you would always know the length
var els = document.querySelectorAll('#divConfirm table')[1].querySelectorAll('tr');
var last = els[els.length - 1];
Another option as the8472's answer suggests would be
document.querySelector('#divConfirm table:nth-child(2) tr:last-child');
Since NodeList doesn't have a pop method.
Using the spread syntax in a new array, then pop() to get the last element.
This basically copy the Nodelist as a regular array, thus the pop() and other array methods become available.
console.log(
// Last elem with pop()
[...document.querySelectorAll("div")].pop()
)
console.log(
// 2nd elem
[...document.querySelectorAll("div")].slice(1)[0]
)
console.log(
// By index :) just in case
document.querySelectorAll("div")[0]
)
<div>The sun</div>
<div>is</div>
<div>shinning</div>
depending on circumstances this may work: document.querySelector('#divConfirm table tr:last-of-type')
You can transform the NodeList into an Array. Then can use array.pop(). It return the last item BUT remove it to the array!
const elementsArray = Array.from(elements);
elementsArray.pop()
Related
Does there exist a function in vanilla JavaScript or jQuery that operates similarly to Node.insertBefore(), but for arrays and/or HTMLCollections?
An example could look something like:
var list = document.getElementsByClassName("stuff");
var nodeToMove = list[0];
var otherNode = list[4];
list.insertBefore(nodeToMove, otherNode);
Basically I'm trying to perform insertBefore() without manipulating the actual DOM, as I want the changes to only be applied to the DOM under certain conditions. If those conditions are met, then I would perform insertBefore() on the actual nodes.
To clarify, I'm looking for a function that would insert an element before a target element at a given index in an array, not necessarily at a given index. Examples I've seen using splice() usually insert an element at a given index, which sometimes puts the element before the target element, and sometimes after, depending on where the element to be moved originally was in the array. I'm looking for something that would reliably put the element to be moved before the target element.
HTMLCollection does not have an insertBefore method. jQuery can apply any jQuery methods both to a single element being selected, as well as many.
https://api.jquery.com/insertBefore/
There is no single method to do this in one step, but there doesn't need to be. If you convert the collection to an Array, you can call the Array.prototype.splice() method to achieve the same result.
Here's an example:
let ary = [1,2,3,4,5];
// Swap 2 and 3
// Start at the 3rd item and remove one item (3).
// Store the removed item
let removed = ary.splice(2,1);
// Start at the second item, don't remove anything, insert the removed
// item at that position
ary.splice(1,null,removed[0]);
// Log the result
console.log(ary);
And, with that knowledge, you can create your own more easily callable function:
let ary = [1,2,3,4,5];
function insertBefore(ary, newItem, target){
ary.splice(target,null,newItem);
}
// Insert 999 before the 3rd array item
insertBefore(ary,999,2)
console.log(ary);
You need to get the index you want, then use Array.splice.
Myself I would do something like this :
const myArr = ['Aurore', 'Dimitri', 'Alban', 'Frédéric'];
const insertBeforeThis = 'Alban';
const eltToInsert = 'Laura';
const index = myArr.findIndex(name => name === insertBeforeThis);
myArr.splice(index, 0, eltToInsert);
Please feel free to try it out in your browser's console. Note i used const for my array, as it fixes the type of the variable as an array but allow me to manipulate it.
MDN: Array.prototype.findIndex()
stackoverflow: How to insert an item into an array at a specific index (JavaScript)?
Have a happy coding time!
Why is it that if I have only one h1 element in the document, I still have to use the index to access it?
Like the following doesn't work.
document.getElementsByTagName('h1').innerHTML = "SHUSHAN";
but if I do
document.getElementsByTagName('h1')[0].innerHTML = "SHUSHAN";
It does work.
Even though I only have one h1, why do I have to specify?
Short answer: This is so that you can have some sanity.
If you don't know whether you will get a single element or a collection of elements, you would have to write defensive, type-checking (stupid) code like this
let foo = document.getElementsByTagName('h1')
if (foo instanceof HTMLCollection)
// do something with all elements
else
// do something with just one element
It makes way more sense for the function to always return a known type, an HTMLCollection of HTMLElement objects
If you only care about getting the first element, you can use destructuring assignment
let [first] = document.getElementsByTagName('h1')
console.log(first) // outputs just the first h1
This is fine because the assignment clearly shows that it's expecting an array (or array-like) of elements but only cares about assigning an identifier to the first value
You should also be aware of the newer document.querySelector and document.querySelectorAll functions …
document.querySelector will select at most one element from the document or returnnull
document.querySelectorAll will always return an HTMLCollection, but may be empty if no elements match the selector.
Here's how I'd write your code in 2017
setTimeout($ => {
// get the element to change
let elem = document.querySelector('h1')
// update the text of the element
elem.textContent = 'SHUSHAN'
}, 3000)
<h1>wait 3 seconds ...</h1>
getElementsByTagName - the method name itself implies that it will return multiple elements - i.e. an array. The method always returns an array, with the length equal to the number of matching elements. As such you must always access the elements by the index of the element in the array.
Arrays must be accessed by index regardless of how many values it holds. Do some reading on array data types to get a better understanding of the concept.
The point is that getElementsByTagName always returns a HTMLCollection of elements, which works mostly as an array. If there is only one element in this collection, then its index is 0.
This is the reason why you must specify the index, even if there is only one element in the document.
Click here or here to see more documentation about this.
$.getJSON('./file-read?filename='+filename+'¶meter='+parameter, function(data) {
var firstElement = data[0][0];
var lastElement = ?
});
I try to find out the last Element in my JSON file.
My JSON File looks like this:
[[1392418800000,6.9],[1392419400000,7],[1392420000000,7.1],[1392420600000,7.2],[1392421200000,7.2]]
can anybody help me to read extract the last date(1392421200000) ?
Just pick the (length - 1)th element with this:
var lastElement = data[data.length-1][0];
Another way is to use array methods, e.g. pop which will return the last element of the array:
var lastElement = data.pop()[0];
N.B.: The first approach is the fastest way of picking the last element, however the second approach will implicitly remove the last element from data array. So if you plan to use the initial array later in your code, be sure to use either the first method or alternative solution provided by #matewka.
VisioN's answer is nice and easy. Here's another approach:
var lastElement = data.slice(-1)[0];
// output: [1392421200000,7.2]
Negative number in the slice method makes the slice count from the end of the array. I find this method more compact and simpler but the disadvantage is that it returns a smaller, 1-element array instead of the element you wanted to fetch. If you want to fetch only the timestamp you'd have to add another [0] to the end of the expression, like this:
var lastElement = data.slice(-1)[0][0];
// output: 1392421200000
You can use :
var data = " any json data";
var lastelement = data[ Object.keys(obj).sort().pop() ];
Object.keys (ES5, shimmable) returns an array of the object's keys. We then sort them and grab the last one.
I want to select some DOM elements into a clone object then I want to remove the last item. After trying it in Chrome console I see that clone's length does not decrease.
Example from Chrome console:
crumbs = $("span",$("div[style='width:390px;background-color:white;'")[0]).clone();
jQuery.fn.jQuery.init[114]
crumbs.last().remove()
[…]
crumbs.length
114
As you see, length is still 114 elements. What am I missing?
crumbs.last().remove() removes the last matched element from the DOM, it doesn't remove it from the jQuery object.
To remove an element from the jQuery object¹ use slice:
var withoutLastOne = crumbs.slice(0, -1);
¹ Actually this will create a new object that matches one less element instead of modifying your existing object. You will usually not care about the distinction, but should be aware of it.
To remove last element from the array you can use below code too.
var arr = ["item1", "item2", "item3", "item4"];
arr.pop();
Demo
As people said, .remove() removes the element from the DOM. Another option than using slice on the final result is to use jquery's filtering before cloning the element:
crumbs = $("span",$("div[style='width:390px;background-color:white;'")[0]).not(':last').clone();
I have the following piece of code that finds all elements in the document with classname foo and then removes them all
function(doc) {
var items = doc.getElementsByClassName('foo');
alert(items.length);
if(items.length>0) {
for(var i=0;i<items.length;i++) {
alert(i);
doc.body.removeChild(items[i]);
}
}
Forexample, the items.length is 3 and the function exits after running one loop and when the length is 8 it exits at 3. Any help would be greatly appreciated. Also, when I run the function again and again it does eventually remove all elements.
Your problem is that the NodeList returned by getElementsByClassName() is live. Either convert it into an array first as Felix suggests or iterate backwards:
var items = doc.getElementsByClassName('foo');
var i = items.length;
while (i--) {
items[i].parentNode.removeChild(items[i]);
}
This works because the item removed from the list each iteration is the last item in the list, therefore not affecting earlier items.
I also changed doc.body to items[i].parentNode for greater generality, in case you need to deal with elements that are not direct children of the <body> element.
The problem is that items is a live NodeList, i.e. whenever you access a property of the list (items.length), the list is reevaluated (elements are searched again).
Since you delete elements in the meantime, the list becomes shorter, but you keep the index.
You could convert the NodeList to an array first:
var items = [].slice.call(doc.getElementsByClassName('foo'));
The array size won't change when you delete the DOM elements.