Iterate through js for loop similarly to nth-child(#n + #) - javascript

Fairly straightforward question; I'm a bit new to JS and was surprised to be unable to find something in my searches.
Within these two for loops, I'm looping through item previews in a Woocommerce shop. Wordpress automatically adds "first" and "last" classes here to adjust margins for styling. I've got a bit of a hacky thing going here where I'm using upsells as a manual recommended products section.
As you'll see below, I'm trying to first wipe out all instances of those classes on every li, then add "last" classes to only some lis: those that work within the columns/ placement I have set up. I'm trying to do this within an if/then statement that checks for screen width. I wasn't having any luck utilizing two separate for loops within each statement, for reasons that are currently a bit over my head.
What I'd like to do: I'd like to automate the for loop to automatically go through every two (or every 3 in the else statement) elements in my upsellLi variable. With CSS you could do something like .upsell .li:nth-child(1n + 2);. I've tried upsellLi([1] + 2); here, but didn't have any luck.
Thank you so much for taking a look!
function columnChange(mobile) {
if (mobile.matches) { // If media query matches variable below function
//If screen size matches variable (is smaller than 1000px wide in our case), change upsell products to have 2 columns
upsellCols.classList.remove('columns-3');
upsellCols.classList.add('columns-2');
//After that, reset first and last columns, then add .last class to 2nd and 4th items to adjust spacing. This assumes a maximum of two rows.
for (var i = 0; i < upsellLi.length; i++ ) {
upsellLi[i].classList.remove('first');
upsellLi[i].classList.remove('last');
upsellLi[1].classList.add('last');
upsellLi[3].classList.add('last');
upsellLi[5].classList.add('last');
//repeat with 5, 7, etc within brackets to add support for more rows
}
} else { //If screen size is larger than 1000px, change upsell products to have 3 columns
upsellCols.classList.remove('columns-2');
upsellCols.classList.add('columns-3');
//After that, reset first and last columns, then add .last class to 3rd and 6th items to adjust spacing. This assumes a maximum of two rows. The "i is already defined" error in Elementor is actually chill because we're only using one for loop at a time thanks to the if/then statement :)
for (var i = 0; i < upsellLi.length; i++ ) {
upsellLi[i].classList.remove('first');
upsellLi[i].classList.remove('last');
upsellLi[2].classList.add('last');
upsellLi[5].classList.add('last');
//repeat with 8, 11, etc within brackets to add support for more rows
}
}
}

Answer per #CBroe in the comments! Here's where I ended up to get this working:
function columnChange(mobile) {
if (mobile.matches) { // If media query matches variable below function
//If screen size matches variable (is smaller than 1000px wide in our case), change upsell products to have 2 columns
upsellCols.classList.remove('columns-3');
upsellCols.classList.add('columns-2');
//After that, reset first and last columns, then add .last class to last product in each row
for (var i = 0; i < upsellLi.length; i++ ) {
upsellLi[i].classList.remove('first');
upsellLi[i].classList.remove('last');
//Add "last" class to every two instances of upsellLi - check if each iteration's number within the loop is divisible by 2. The 1 at the end offsets the count to start on the second iteration (since the count starts at 0)
if(i % 2 === 1) {
upsellLi[i].classList.add('last');
}
}
} else { //If screen size is larger than 1000px, change upsell products to have 3 columns
upsellCols.classList.remove('columns-2');
upsellCols.classList.add('columns-3');
//After that, reset first and last columns, then add .last class to last product in each row
for (var i = 0; i < upsellLi.length; i++ ) {
upsellLi[i].classList.remove('first');
upsellLi[i].classList.remove('last');
//Add "last" class to every 3 instances of upsellLi - check if each iteration's number within the loop is divisible by 3. The 2 at the end offsets the count to start on the third iteration (since the count starts at 0)
if(i % 3 === 2) {
upsellLi[i].classList.add('last');
}
}
}
}

Related

How to randomly select divs from inside another div?

I am struggling to randomly select some divs (9 in this case) to place bombs/mines for those selected tiles.
My code for this is:
function place_mines() {
if (document.getElementById("difficulty").selectedIndex == "2") {
for (var u = 0; u < 8; u++) {
}
}
}
Inspected the element, grid which contains all the tiles.
I would use a different approach. I would make a list of tile objects and generate the html from the list. This lets you flag an object as bomb without revealing it to the user by adding it as class name.
After you generated the list, you can take a random subset and flag it as bombs. You could use this approach for example: Sampling a random subset from an array.
I suggest you to give id to the tiles, to later you generate random id , and map the generated id to the tiles
What worked for me was I added a counter to index the elements.
After that, made an array of 9 random numbers from 0-80 (counter starts at 0), checked if the id of the tile selected is in that array, if it was then that tile has a mine else its a normal tile.
tile.setAttribute("id",counter);counter++;

Is there a function to get the next 10 rows for Sqlite3?

I would like to displaying the next 5 rows of my Sqlite table using button(<) pre 5 or button(>) next 5 of my row.
I read on the sqliteWebSite sqlitetutorial a function call's Rank.
It's a little bit difficult to understand for me how that will work.
It will be very helpfull if i get an easy example.
As rAndom69 mentioned, you will want to combine the OFFSET and LIMIT keywords.
OFFSET tells Sqlite to skip the first x number of rows, while LIMIT tells it to return the next y number of rows.
For example, if you wanted to start at the 100th row of your table and return the next 10, you would do something like:
SELECT *
FROM someTable
LIMIT 10 OFFSET 100;
Please check this
The RANK() function is a window function that assigns a rank to each row in a query’s result set. The rank of a row is calculated by one plus the number of ranks that comes before it.
SELECT
Val,
RANK () OVER (
ORDER BY Val
) ValRank
FROM
RankDemo;
For More information show this link :
http://www.sqlitetutorial.net/sqlite-window-functions/sqlite-rank/

Javascript error with if statement inside of a for loop/array insertion and construction

Backstory and Context: I will do my best to explain what I am working on, where the problem is that I have identified, and my thought process for my current code. Bear with me as I will try to provide as much detail as possible. Note that I am still learning Quartz Composer and am rather unfamiliar with Javascript syntax.
I am working with Quartz Composer to modify the visual equalizer template that comes with the program. Essentially, my audio feed gets input into the program where it is processed as 16 audio frequency bands that are stored in an array. Each of these 16 bands corresponds to the magnitude of the frequency in that range, and will ultimately display on a "bar graph" with the various equalizer levels. This part is all well and good.
My task requires that I have more than 16 bars in my graph. Since I cannot split the audio any further without turning to a somewhat complicated external process, I figured I could just fake my way through by inserting fake bar and values in between the actual audio bars that would average or evenly space themselves in between the true audio bar values.
For example, suppose that my input array looked as such "A B C" where "A," "B," and "C" are some audio value. I declare in my code a certain "insertion" value that determines how many fake bars are to be added in between each of my true audio values. In the case of "A B C," suppose that the insertion value were set to 0. No bars are to be inserted, thus the output array is "A B C." Suppose that the insertion value is set to 1. 1 bar is to be inserted in between each of the true values, returning an array of "A (A+B)/2 B (B+C)/2 C." As such, if the insertion value is set to 2, two values will be placed between A and B such that they are evenly spaced in between, aka 1/3 and 2/3rds of the way between A and B respectively.
Relevant Code:
var array = new Array();
function (__structure outputStructure) main (__structure inputStructure, __number insertions, __number time) {
var result = new Object();
/* check if the input array for the sound bands is null or not */
if (inputStructure != null) {
/* keep track of the number of times that a value is inserted so that, upon the counter being reset, a value from the original array can be inserted */
var counter = 0;
/* keep track of which index location the original array value is to be pulled from */
var inputPlace = 0;
/* build a new array that inserts a number of values equal to the value of the insertions variable in between all values of the original array */
for (i=0; i<((insertions + 1) * (inputStructure.length - 1) + 1); ++i) {
/* if it is time to do so, pull a true audio bar value from the original string into the new string */
if (counter = 0) {
array[i] = inputStructure[inputPlace];
/* if it is not time to pull a value from the original array, insert the specified number of evenly spaced, calculated bar values into the new array */
} else {
/* space the insertion between the nearest two true values from the original input array */
array[i] = inputStructure[inputPlace] + ((inputStructure[inputPlace + 1] - inputStructure[inputPlace]) * counter / (insertions + 1));
}
counter = counter + 1;
/* reset the counter after each complete iteration of insertions is compelte so that an original array value can be pulled into the new array */
if (counter > insertions) {
counter = 0;
inputPlace = inputPlace + 1;
}
counter = counter + 1;
}
}
result.outputStructure = array;
return result;
}
In this particular code, I do not have any inputs manually declared, as they will all be pulled in from Quartz Composer. I have had no problems with this part. I assume for testing purposes, you could just hard code in values for the inputStructure, insertion, and time.
Problem:
The problem that I have identified seems to be with the if statement inside of my for loop. When I run the code, it sets every value in the new array to 0.
Question: I guess my question is what am I doing wrong with the if statement in the for loop that is causing it to overwrite all of my other iteration values? I was able to get the counter working such that each iteration would return the counter value "0 1 2 0 1 2" in the case of the insertion being set to 2, but I was unable to say okay, now check during each iteration, and if the counter is 0, pull a value from the original array. Otherwise, do something else, in this case, calculate and add the fake bar value into the new array.
Your problem is this line:
if (counter = 0) {
It will always return false, to compare you need to use == or ===

Continuously loop colors on div using javascript on mouseenter

I have a div on a page and I would like to continuously cycle through a set of colors using javascript.
I've seen a number of articles on Stack Overflow about continuous loops to show information using arrays and javascript yet I have had trouble trying to implement it into my own project.
My HTML:
<div id="box" style="background:grey;" onmouseenter="change()"></div>
and the closest JS solution I can find:
var change = function() {
colors = ['#00b0e2', '#e3144e', '#15e39b'];
count = -1;
return function() {
return colors[++count % colors.length];
}
document.getElementById('box').style.background = colors; // or should this be **colors[]**?
}
I understand what is happening up until the return function but then I am having trouble understanding how to inject the color into the html?
Any help or tips would be appreciated thanks.
I think you are really close, but are missing a couple of key things.
Firstly, when you say onmouseover="change()" that means that it will run change() every time the mouseover runs unlike using addEventListener(change()) which would run the function returned by change as the event handler.
Secondly to change the element, all you need to do is get a handle on the element and set the background.
The code below does what I think you were trying to do but more simply. I hope it helps.
// setup our colors and state once
colors = ['#00b0e2', '#e3144e', '#15e39b'];
count = -1;
var change = function(element) {
element.style.background = colors[++count % colors.length];
}
<!-- Pass in the element when creating the change listener -->
<div id="box" style="background:grey;" onmouseenter="change(this)">
Give our box some contents so we can see it.
</div>
Explanation:
the basic concept behind the loop is that we have a count that tells us colors[count] is currently active.
When a mouseover happens, three things happen in the one line.
++count: this adds 1 to count, but unlike count++, it does so before the value is used. Meaning that the first time a mouseover occurs, the value of count is 0
count % colors.length: This just lets us wrap around to the first color once it has hit the last color. The % (modulus) operator gives the remainder. a % b will return the remainder after dividing a / b. If count = 0, count % 3 yields 0, but if count = 4, count % 3 yields 1. You can read more about this and other Arithmetic operators on MDN
element.style.background = colors[...]: This sets the background css attribute to the color we selected in the last step.
so to put it all together, here is the change function broken out into 3 lines.
var change = function(element){
count++; //increment count before using it.
var our_color = count % colors.length; // wrap properly
element.style.background = colors[our_color];
}

Get all elements in viewport Javascript

I wonder if it is possible (in javascript or jquery but without any plugins) to get all elements (for example table rows tr) in current viewport without looping through each of them? I found a lot of examples how to check if specified element is in current viewport, but what I need is a function returns a list of all elements in current viewport. I need this for virtualization because this table should have an infinite capacity and looping through each row from two millions rows is quite inefficient :)
Is there any reasonable way to do this?
Assuming you're not doing anything fancy with positioning, table rows in the viewport can be found with a binary search. For example, for 200000 rows, about 18 lookups are required to locate the first row on the page (jsfiddle, warning: slow to load). This can be extended to find the last element as well, or you could just loop through the elements starting from the first until you find one that is no longer visible.
var rows = table.children().children();
var start = 0;
var end = rows.length;
var count = 0;
while(start != end) {
var mid = start + Math.floor((end - start) / 2);
if($(rows[mid]).offset().top < document.documentElement.scrollTop)
start = mid + 1;
else
end = mid;
}
Obviously this does not work well if anything is floated, absolutely positioned, etc. In short: The nodes being searched must be in order such that rows[N-1].top <= rows[N].top. For something such as a table, this should be true if no styling is applied and no multi-row cells exist.

Categories

Resources