I am trying to figure out how to build a forEach loop with an unknown number of elements. Randomly pick one, do XYZ to it. Make it visible. Remove that element from consideration. Repeat picking a random number from remaining elements.
My thoughts so far are to make an array of the elements id's. Use the array.forEach() to loop over them. Select an element at random from the array. Execute XYZ then remove selected id from array then repeat till forEach expires.
So first of all if you can think of a better way I'm open to any and all ideas.
I didn't get far before I hit my first roadblock and that is dynamically generating the array of id's.
I get the number of elements (they will always be children of the parent so no worries there.
//get count of all elements and loop till all are visible
var elementCount = $('#PartialsContainer').children().size();
Next I goto generate my array but it results in one element in the array holding the value of elementCount.
//create array of quantity
var elementArray = $.makeArray( elementCount );
So I could do a loop through elements getting their id like this but surely there is a better way?
for (var i = 0; i < elementCount; i++)
{
elementArray.push( $element[i] //its pseudo code I know it won't work );
}
Thank you for any ideas / tips on improving this design / approach.
Try something like
var $els = $('#PartialsContainer').children();
while($els.length){
var $el = $els.eq(Math.floor(Math.random() * $els.length));
//do something with $el
$els = $els.not($el);
}
Demo: Fiddle
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!
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()
So I have been searching for a couple of hours now and I haven't really found a solution yet.
It seems that the jQuery method .index() when calling on an element in a set, does not take the selector into regard.
To clarify, when I have a list of 5 li elements, where element 2, 3 and 4 have the class "foo". When I first filter these items with $('li.foo'), I get a set back with the size of 3 elements big. When I perform the .index() on the first item in the set like so $('li.foo').first().index(), instead of returning 0 (since it's the first item in the set and index starts counting from 0), it actually returns 1 (or in other words, the index for the second item).
Now with the example above it doesn't really seem necessary in my example to use index, but in my code I actually filter the filtered set( $('li.foo').filter('.active') ) to get a single item and then get the index of that item.
The problem it seems is that .index ignores the filters and selectors and I haven't had any luck in $.inArray();
If anyone could shed some light on how to get the index with a sure fire way, I would be super grateful!!
The index method have multiple variants to help in this regard
One you can call it on a set of elements and pass the element whose index has to be found as an argument
var $lis = $('li.foo');
var idx = $lis.index($lis.first());//will return 0
Another way is to pass the selector as an argument then index will return the index value based on the position of the current element relative to position of the element in the element set returned by the set of elements
var $el = $('li.foo').first();
var idx = $el.index('li.foo');
As for your problem
var $lis = $('li.foo'), $active = $('li.foo').filter('.active');
var index = $lis.index($active)
I have this collection of images resources where that is stored in array, the user will select an image and then the selected image will be removed from the list(also from the array) and after that The array would be rearrange. How could I perform such task? (as much as possible I do not want to use an open source library)
Sounds like you need to look up splice() method. It allows you to add and remove one to many items within an array at any index.
here's reference for it.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/splice
your question lacks a code example but you can use Array.splice(index,number) whereas index is zero based and number is how many items to remove.
images.splice(selectedIndex,1);
Simply, you can create a temporary array where you store the initial array elements you need and reassign the value of your initial array to the temporary array.
function clean_array(my_array){
var no_need_value = 'value you want to remove'
var tmpArray = new Array()
for (var i = 0; i < my_array.length; i++)
if (my_array[i] != no_need_value)
tmpArray.push(my_array[i])
my_array = tmpeArray
}
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.