So here is an example of the function I need to replicate:
document.getElementById('img1').onmouseover = function() {
document.getElementById('img1').style.width = expandTo + '%';
expandCompensate(1);
}
document.getElementById('img1').onmouseout = function() {
expandReset();
}
The situation is that I have a for loop creating some div elements, and the number of them is dynamic. As of right now, I have it creating 4 div elements, so I created 4 iterations of the above functions for img1, img2, img3 and img4. But what I would like to do is to have the onmouseover and onmouseout functions created dynamically based on how many div elements I've decided to create (based on a variable).
Is there any way to do this? Here is all the code for context (it's not much), there are comments in the JS with explanations for everything. The part I'm trying to automate is at the bottom:
https://jsfiddle.net/4w0714su/3/
And here is the working example for context of what I'm trying to achieve:
http://www.ericsartor.ca/imgwide
FYI: The image is I picked were random, I just needed high res images. Just doing this for practice! Thanks to anyone that can help me figure this out!
I can't understand your code very well, but I'll answer particularly what you're asking.
You can achieve what you want by doing a loop:
for (var i = 0; i < 4; i++) {
document.getElementById('img' + i).onmouseover = function() {
this.style.width = expandTo + '%';
expandCompensate(Number(this.id.replace('img', '')));
};
document.getElementById('img' + i).onmouseout = function() {
expandReset();
}
}
Note: you can't use the i variable inside the event handlers' functions, because it will always be 4, since it will finish the loop, and will never be changed again.
Another way of doing that is by using an IIFE (Immediately-invoked function expression), e.g:
for (var i = 0; i < 4; i++) {
(function(n) {
document.getElementById('img' + n).onmouseover = function() {
this.style.width = expandTo + '%';
expandCompensate(n);
};
document.getElementById('img' + n).onmouseout = function() {
expandReset();
}
})(i);
}
Doing that, you're passing to a function the current i value, so in that scope, the value of n will be a different one for each execution, e.g 0, 1, 2 and 3.
An immediately-invoked function expression (or IIFE, pronounced
"iffy") is a JavaScript design pattern which produces a lexical scope
using JavaScript's function scoping.
This could be achieved by iterating all those DOM elements and binding events in a loop.
As we bind events in loop, and event callback is being executed later when loop would be iterated completely, we need to maintaing the value of current iteration using CLOSURE.
Try this snippet:
var pageHeight = document.getElementById('findBottom').getBoundingClientRect().bottom,
numOfPics = 4; //the number of div elements to create
//creates the div elements within a container div in the HTML document
for (var i = 1; i <= numOfPics; i++) {
document.getElementById('imgContain').innerHTML += '<div id="img' + i + '" class="imgPane"></div>';
}
//used to resize all divs if the window changes size
window.onresize = function() {
pageHeight = document.getElementById('findBottom').getBoundingClientRect().bottom;
for (var i = 1; i <= imgClasses.length; i++) {
document.getElementById('img' + i).style.height = pageHeight + 'px';
}
for (var i = 1; i <= imgClasses.length; i++) {
document.getElementById('img' + i).style.width = 100 / imgClasses.length + '%';
}
};
//sets the height of each div to be the mximum height of the page (without scrolling)
for (var i = 1; i <= numOfPics; i++) {
document.getElementById('img' + i).style.height = pageHeight + 'px';
}
//makes all the divs equal percentage widths
for (var i = 1; i <= numOfPics; i++) {
document.getElementById('img' + i).style.width = 100 / numOfPics + '%';
}
//the percentage of the page the hovered image will expand to
var expandTo = 40;
//function for when an image is hovered over
function expandCompensate(whichImg) {
for (var i = 1; i <= numOfPics; i++) {
if (i != whichImg)
document.getElementById('img' + i).style.width = (100 - expandTo) / (numOfPics - 1) + '%';
}
}
//function for when the hovered image is left to reset the widths
function expandReset() {
for (var i = 1; i <= numOfPics; i++) {
document.getElementById('img' + i).style.width = 100 / numOfPics + '%';
}
}
(function bindEvents() {
for (var i = 1; i <= numOfPics; i++) {
document.getElementById('img' + i).onmouseover = (function(i) {
return function() {
document.getElementById('img' + i).style.width = expandTo + '%';
expandCompensate(i);
}
})(i);
document.getElementById('img' + i).onmouseout = function() {
expandReset();
};
}
})();
body,
p,
div {
margin: 0;
padding: 0;
}
body {} #findBottom {
position: absolute;
bottom: 0;
}
.imgPane {
float: left;
background-position: center;
transition: width 0.25s;
}
#img1 {
background-image: url('http://www.ericsartor.ca/imgwide/img//1.jpg');
}
#img2 {
background-image: url('http://www.ericsartor.ca/imgwide/img//2.jpg');
}
#img3 {
background-image: url('http://www.ericsartor.ca/imgwide/img//3.jpg');
}
#img4 {
background-image: url('http://www.ericsartor.ca/imgwide/img//4.jpg');
}
<div id="imgContain"></div>
<!-- ABSOLUTE ELEMENTS -->
<div id="findBottom"></div>
<!-- ABSOLUTE ELEMENTS -->
Related
Fairly easy solution to this problem, I'm pretty sure, but I'm still currently unable to find where the problem may be (probably some syntax).
I'm trying to create a simple JS exercise to move an object's position to a random place after each hover/mouseover. (DOM manipulations fundamentals).
Here is the code:
let arr = [".top", ".left"];
let logTest = []
document.querySelectorAll('div').forEach(occurence => {
occurence.addEventListener('mouseover', (e) => {
for (let i = 0; i < 2; i++) {
var num = Math.floor((Math.random() * 100) + 1);
e.target.style[arr[i]] = num + "px";
logTest[i] = num + "px";
}
console.log(logTest[0] + ", " + logTest[1]);
});
});
Since the numbers are being generated and printed correctly to the console, I'm fairly sure that the problem has to be in line 9, where e.target.style[.left and .top] is not being able to be assigned to the random numbers.
let arr = [".top", ".left"];
Don't use '.' dots for specifying the style. Directly use the style property name. Use this:
let arr = ["top", "left"];
And make sure to set position as relative, absolute or fixed for the div elements.
Here's a working example made using your script:
<style>
.t {
height: 50px;
width: 50px;
background: green;
margin: 10px;
position: relative;
}
</style>
<h1>Hello</h1>
<div class="t">e</div>
<div class="t">f</div>
<script>
let arr = ["top", "left"];
let logTest = []
document.querySelectorAll('div').forEach(occurence => {
occurence.addEventListener('mouseover', (e) => {
for (let i = 0; i < 2; i++) {
var num = Math.floor((Math.random() * 100) + 1);
e.target.style[arr[i]] = num;
logTest[i] = num;
}
console.log(logTest[0] + ", " + logTest[1]);
});
});
</script>
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Background: I am working on a dashboard, which shows a header and a table underneath. The table can have many rows (over 100).
Problem: large number of rows triggers a vertical scrollbar to show up, which hides the rest of the rows.
Possible solution: I would like to rotate, what table rows are showed on every screen the dashboard is on. I would like to avoid to set a fixed number of rows that are visible on screen and instead, determine how many rows can be put on the screen before the scroll bar shows up. This means that, first, I would like to determine how many rows are visible on the screen before the scrollbar shows up, and then create a carousel animation, where the next X rows are showed until all the rows are showed and the animation resets.
Technologies used: React JS, Bootstrap table
For the carousel part, I found Bootstrap Carousel to work fine, but the problem is figuring out, how many rows are visible on the screen. How do I determine, how many rows I can display on the screen before the scroll-bar shows up? Thank you very much!
One possible solution would be:
Create an element in the DOM which would be 100% height (any other possible height will work too). For example:
<div id="row-wrapper" style="height: 100%"></div>
Get the height of the element.
var availableHeight = document.getElementById('row-wrapper').clientHeight;
Knowing how much height your single row occupies just divide availableHeight and you will know how many rows to render. In case your row height is 30:
var numberOfRows = Math.floor(availableHeight / 30);
I know you tagged ReactJS, but a good basis is to always keep your DOM as small as possible. My tactic would be to keep the data in JavaScript and only introduce to the DOM what is absolutely needed.
Below is a simple example showing 10 rows with an offset:
var dummyData = [];
(function populateData() {
var names = ["Greg", "Jeff", "Bob", "Bruce", "Clark", "Diana"];
while (dummyData.length < 100000) {
dummyData.push({
name: names[Math.floor(Math.random() * names.length)],
age: Math.floor(Math.random() * 100)
});
}
})();
function displayData(data, offset, limit) {
if (offset === void 0) {
offset = 0;
}
if (limit === void 0) {
limit = data.length;
}
var tbody = document.body.appendChild(document.createElement("tbody"));
for (var i = offset; i < (limit + offset); i++) {
if (i >= data.length) {
break;
}
var person = data[i];
var tr = tbody.appendChild(document.createElement("tr"));
tr.innerHTML = "<td>" + i + "</td><td>" + person.name + "</td><td>" + person.age + "</td>";
}
return tbody;
}
var pagesize = 10;
var offset = 0;
var offsetInput = document.body.appendChild(document.createElement("input"));
offsetInput.type = "number";
offsetInput.min = "0";
offsetInput.value = "0";
var table = document.body.appendChild(document.createElement("table"));
table.style.width = "100%";
table.innerHTML = "<thead><tr><th>Index</th><th>Name</th><th>Age</th></tr></thead>";
var tbody = table.appendChild(displayData(dummyData, offset, pagesize));
function update() {
if (offsetInput.validity.valid) {
offset = parseInt(offsetInput.value, 10);
table.removeChild(tbody);
tbody = displayData(dummyData, offset, pagesize);
table.appendChild(tbody);
}
}
offsetInput.addEventListener("change", update);
offsetInput.addEventListener("keyup", update);
From here it would be a matter of some CSS tricking and reading the scrollbar to get an offset.
var dummyData = [];
(function populateData() {
var names = ["Greg", "Jeff", "Bob", "Bruce", "Clark", "Diana"];
while (dummyData.length < 100) {
dummyData.push({
name: names[Math.floor(Math.random() * names.length)],
age: Math.floor(Math.random() * 100)
});
}
})();
function displayData(data, offset, limit) {
if (offset === void 0) {
offset = 0;
}
if (limit === void 0) {
limit = data.length;
}
var tbody = document.body.appendChild(document.createElement("tbody"));
for (var i = offset; i < (limit + offset); i++) {
if (i >= data.length) {
break;
}
var person = data[i];
var tr = tbody.appendChild(document.createElement("tr"));
tr.innerHTML = "<td>" + i + "</td><td>" + person.name + "</td><td>" + person.age + "</td>";
}
return tbody;
}
var pagesize = 10;
var offset = 0;
var offsetInput = document.body.appendChild(document.createElement("input"));
offsetInput.type = "number";
offsetInput.min = "0";
offsetInput.max = "" + (dummyData.length - pagesize);
offsetInput.value = "0";
var outerContainer = document.body.appendChild(document.createElement("div"));
outerContainer.style.maxHeight = "400px";
outerContainer.style.width = "450px";
outerContainer.style.overflowY = "scroll";
var innerContainer = outerContainer.appendChild(document.createElement("div"));
innerContainer.style.height = dummyData.length * 20 + 200 + "px";
var table = innerContainer.appendChild(document.createElement("table"));
table.style.position = "absolute";
table.style.width = "400px";
table.innerHTML = "<thead><tr><th>Index</th><th>Name</th><th>Age</th></tr></thead>";
var tbody = table.appendChild(displayData(dummyData, offset, pagesize));
var handle;
function update() {
table.removeChild(tbody);
tbody = displayData(dummyData, offset, pagesize);
table.appendChild(tbody);
clearTimeout(handle);
handle = setTimeout(function() {
offsetInput.value = offset.toString();
outerContainer.scrollTop = offset * 20;
}, 100);
}
function updateInput() {
if (offsetInput.validity.valid) {
offset = parseInt(offsetInput.value, 10);
}
update();
}
function updateScroll() {
offset = Math.floor(outerContainer.scrollTop / 20);
update();
}
outerContainer.addEventListener("scroll", updateScroll);
offsetInput.addEventListener("change", updateInput);
offsetInput.addEventListener("keyup", updateInput);
This is an example how you can fill a div until its full. Made a jQuery answer too if someone is interested in that.
I made 2 div's. One with a set height(100% in the example but can be static height too) and inside a growable div that grows with the content.
First it will fill the growable div as long it is smaller then the content div.
The last added element could be bigger then the remaining space. If that happens it removes the last element.
This also works with content with dynamic heights.
Note: When using while loops it's always good to have a backup plan to avoid infinite loops. Therefore I added a max records variable.
Javascript:
window.onload = function() {
document.getElementById('fill').onclick = function() {
var content = document.getElementById('content');
var growableWrapper = document.getElementById('growableWrapper');
var maxRecords = 50;
while ((content.childNodes.length === 0 || parseInt(window.getComputedStyle(growableWrapper).height) < parseInt(window.getComputedStyle(content).height)) && growableWrapper.childNodes.length < maxRecords) {
var newElement = document.createElement("p");
var newText = document.createTextNode("Test");
newElement.appendChild(newText);
growableWrapper.appendChild(newElement);
}
if (window.getComputedStyle(growableWrapper).height > window.getComputedStyle(content).height && growableWrapper.childNodes.length > 1) {
growableWrapper.removeChild(growableWrapper.childNodes[growableWrapper.childNodes.length - 1]);
}
}
}
html,
body,
#content {
margin: 0;
padding: 0;
height: 100%;
}
#fill,
#content {
width: 40%;
float: left;
}
#content {
background-color: gray;
overflow: hidden;
}
#growableWrapper {
background-color: lightgray;
overflow: auto;
}
<div>
<button id="fill">Fill</button>
</div>
<div id="content">
<div id="growableWrapper">
</div>
</div>
jQuery:
$(document).ready(function() {
$('#fill').on('click', function() {
var content = $('#content');
var growableWrapper = $('#growableWrapper');
var maxRecords = 50;
while ((content.children().length === 0 || growableWrapper.height() < content.height()) && growableWrapper.children().length < maxRecords) {
growableWrapper.append('<p>test</p>');
}
if(growableWrapper.height() > content.height() && growableWrapper.children().length > 1) {
growableWrapper.children().last().remove();
}
});
});
html,
body,
#content {
margin: 0;
padding: 0;
height: 100%;
}
#fill, #content {
width: 40%;
float: left;
}
#content {
background-color: gray;
overflow: hidden;
}
#growableWrapper {
background-color: lightgray;
overflow: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<button id="fill">Fill</button>
</div>
<div id="content">
<div id="growableWrapper">
</div>
</div>
Please scroll down to bold text if you want to go straight to the question
I have made a page that consists of a grid of 9 tiles (divs).
Between 1-9 of those tiles could potentially have a slider inside it.
The sliders are all setup via a jQuery each function e.g
_gridSlider.each(function(){
// count slides, setup slider etc
}); // end slider each function
Everything works fine except the sliders all change at the same time and so I want to add some diversity into the start times.
Right now I create a random ID between 1 and X (X being the number of sliders) inside of the each function for each slider like so
_gridSlider.each(function(){
var _sliderID = Math.floor((Math.random() * _numSliders) + 1);
}); // end slider each function
I then start the sliders at a different time based around this ID like so
var _sliderStart = _sliderID + '000';
setTimeout(function() {
startTimer();
}, _sliderStart);
This works fine the only problem is that it is possible for 2 or more sliders to have the same ID, what I need is to assign each slider an ID between 1 and X but make sure that each slider has a different ID.
The end result would be have 1 timer starting at 1 second, another at 2 seconds, another at 3 seconds etc
You can use this function:
function generateId(numSliders) {
var store = generateId._store;
if (!store) {
generateId._store = {};
}
do {
var id = Math.floor(Math.random()*numSliders*1000+1);
} while (store[id])
store[id] = true;
return id;
}
Then you can use generated id as a start time:
var sliderId = generateId(slidersNumber);
var sliderStart = sliderId; // without + '000'
UPD generateId._store keeps used IDs inside itself. In that function store is used as a property of its function, to not add redundant variable to the namespace. You can put it outside of the generateId function. For example:
var store = {};
function generateId(numSliders) {
do {
var id = Math.floor(Math.random()*numSliders*1000+1);
} while (store[id])
return id;
}
But in that case you're polluting the namespace with redundant variable.
store inside of the function is used just to shorten the code a little. If you want you can write:
function generateId(numSliders) {
if (!generateId._store) {
generateId._store = {};
}
do {
var id = Math.floor(Math.random()*numSliders*1000+1);
} while (generateId._store[id])
generateId._store[id] = true;
return id;
}
An example using shuffle.
function createNumberSeries(howMany) {
var result = [];
for (var count = 1; count <= howMany; count += 1) {
result.push(count);
}
return result;
}
function shuffle(obj) {
var i = obj.length;
var rnd, tmp;
while (i) {
rnd = Math.floor(Math.random() * i);
i -= 1;
tmp = obj[i];
obj[i] = obj[rnd];
obj[rnd] = tmp;
}
return obj;
}
function createDivs(ids) {
var length = ids.length;
for (var index = 0; index < length; index += 1) {
var div = document.createElement('div');
div.id = ids[index];
div.className = 'initial';
document.body.appendChild(div);
}
}
function colourDivs(howMany) {
for (var index = 1; index <= howMany; index += 1) {
setTimeout((function(id) {
return function() {
document.getElementById(id).className += ' colorMe';
};
}(index)), index * 1000);
}
}
var numSliders = 10;
var sliderIds = shuffle(createNumberSeries(numSliders));
createDivs(sliderIds);
colourDivs(numSliders);
.initial {
height: 10px;
width: 10px;
border-style: solid;
border-width: 1px;
}
.colorMe {
background-color: blue
}
I am trying to render the list based on virtual rendering concept. I am facing some minor issues, but they are not blocking the behaviour. Here is the working fiddle http://jsfiddle.net/53N36/9/ and Here are my problems
Last items are not visible, I assume some where I missed indexing.(Fixed, Please see the edit)
How to calculate scrollPosition if I want to add custom scroll to this.
Is this the best method or any other?
I have tested it with 700000 items and 70 items in chrome. Below is the code
(function () {
var list = (function () {
var temp = [];
for (var i = 0, l = 70; i < l; i++) {
temp.push("list-item-" + (i + 1));
}
return temp;
}());
function listItem(text, id) {
var _div = document.createElement('div');
_div.innerHTML = text;
_div.className = "listItem";
_div.id = id;
return _div;
}
var listHold = document.getElementById('listHolder'),
ht = listHold.clientHeight,
wt = listHold.clientWidth,
ele = listItem(list[0], 'item0'),
frag = document.createDocumentFragment();
listHold.appendChild(ele);
var ht_ele = ele.clientHeight,
filled = ht_ele,
filledIn = [0];
for (var i = 1, l = list.length; i < l; i++) {
if (filled + ht_ele < ht) {
filled += ht_ele;
ele = listItem(list[i], 'item' + i);
frag.appendChild(ele);
} else {
filledIn.push(i);
break;
}
}
listHold.appendChild(frag.cloneNode(true));
var elements = document.querySelectorAll('#listHolder .listItem');
function MouseWheelHandler(e) {
var e = window.event || e;
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
console.log(delta);
//if(filledIn[0] != 0 && filledIn[0] != list.length){
if (delta == -1) {
var start = filledIn[0] + 1,
end = filledIn[1] + 1,
counter = 0;
if (list[start] && list[end]) {
for (var i = filledIn[0]; i < filledIn[1]; i++) {
if (list[i]) {
(function (a) {
elements[counter].innerHTML = list[a];
}(i));
counter++;
}
}
filledIn[0] = start;
filledIn[1] = end;
}
} else {
var start = filledIn[0] - 1,
end = filledIn[1] - 1,
counter = 0;
if (list[start] && list[end]) {
for (var i = start; i < end; i++) {
if (list[i]) {
(function (a) {
elements[counter].innerHTML = list[a];
}(i));
counter++;
}
}
filledIn[0] = start;
filledIn[1] = end;
}
}
//}
}
if (listHold.addEventListener) {
listHold.addEventListener("mousewheel", MouseWheelHandler, false);
listHold.addEventListener("DOMMouseScroll", MouseWheelHandler, false);
} else listHold.attachEvent("onmousewheel", MouseWheelHandler);
}());
Please suggest me on this.
EDIT:
I have tried again and I am able to fix the indexing issue. http://jsfiddle.net/53N36/26/
But how can I calculate the scroll position based on the array list currently displayed.
Is this the best method or any other?
I think something that would make this much easier is not to try to handle scrolling yourself.
In this fiddle I show that you can let the browser handle scrolling for you, even though we are using virtual rendering.
Using .scrollTop I detect where the browser thinks the user is looking, and I draw in items based on that.
You'll note that if you set hidescrollbar to false and the user uses it to scroll, my method still runs fine.
Therefore, to calculate scroll position you can just use .scrollTop.
And as for custom scrolling, just make sure you influence the .scrollTop of #listHolder and recall refreshWindow()
CODE FROM FIDDLE
(function () {
//CHANGE THESE IF YOU WANT
var hidescrollbar = false;
var numberofitems = 700000;
//
var holder = document.getElementById('listHolder');
var view = null;
//get the height of a single item
var itemHeight = (function() {
//generate a fake item
var div = document.createElement('div');
div.className = 'listItem';
div.innerHTML = 'testing height';
holder.appendChild(div);
//get its height and remove it
var output = div.offsetHeight;
holder.removeChild(div);
return output;
})();
//faster to instantiate empty-celled array
var items = Array(numberofitems);
//fill it in with data
for (var index = 0; index < items.length; ++index)
items[index] = 'item-' + index;
//displays a suitable number of items
function refreshWindow() {
//remove old view
if (view != null)
holder.removeChild(view);
//create new view
view = holder.appendChild(document.createElement('div'));
var firstItem = Math.floor(holder.scrollTop / itemHeight);
var lastItem = firstItem + Math.ceil(holder.offsetHeight / itemHeight) + 1;
if (lastItem + 1 >= items.length)
lastItem = items.length - 1;
//position view in users face
view.id = 'view';
view.style.top = (firstItem * itemHeight) + 'px';
var div;
//add the items
for (var index = firstItem; index <= lastItem; ++index) {
div = document.createElement('div');
div.innerHTML = items[index];
div.className = "listItem";
view.appendChild(div);
}
console.log('viewing items ' + firstItem + ' to ' + lastItem);
}
refreshWindow();
document.getElementById('heightForcer').style.height = (items.length * itemHeight) + 'px';
if (hidescrollbar) {
//work around for non-chrome browsers, hides the scrollbar
holder.style.width = (holder.offsetWidth * 2 - view.offsetWidth) + 'px';
}
function delayingHandler() {
//wait for the scroll to finish
setTimeout(refreshWindow, 10);
}
if (holder.addEventListener)
holder.addEventListener("scroll", delayingHandler, false);
else
holder.attachEvent("onscroll", delayingHandler);
}());
<div id="listHolder">
<div id="heightForcer"></div>
</div>
html, body {
width:100%;
height:100%;
padding:0;
margin:0
}
body{
overflow:hidden;
}
.listItem {
border:1px solid gray;
padding:0 5px;
width: margin : 1px 0px;
}
#listHolder {
position:relative;
height:100%;
width:100%;
background-color:#CCC;
box-sizing:border-box;
overflow:auto;
}
/*chrome only
#listHolder::-webkit-scrollbar{
display:none;
}*/
#view{
position:absolute;
width:100%;
}
In this function, it should give the menu items (li's) an specific background (png) out of an array. However; it doesn't. It gives all the li's the background called color 'blue' :(.
Do you see the problem?
//Gives the menu items a style when hovering over it, in the sequence of the setting in the variable 'backgrounds', on top.
var backgrounds = ["blue", "green", "pink", "purple"];
function MenuColorChange() {
for (var i = 0; i <= 10 ; i++) {
document.getElementById("custom-menu-item-id-" + (i + 1)).onmouseover = function() {
this.style.backgroundImage= "url(images/" + backgrounds[(i % backgrounds.length)] + ".png)";
}
document.getElementById("custom-menu-item-id-" + (i + 1)).onmouseout = function() {
this.style.background = 'none';
MenuActiveColor();
}
}
}
Html:
<ul>
<li id="custom-menu-item-id-1">
<a href="#">
Home
</a>
</li>
/* And 3 li's more... */
</ul>
The function you use for onmouseover is a closuse of the outer function, in the time it is executed all onmouseover handlers have the save value of i, to achieve what you seen to want do:
//Gives the menu items a style when hovering over it, in the sequence of the setting in the variable 'backgrounds', on top.
var backgrounds = ["blue", "green", "pink", "purple"];
function MenuColorChange() {
for (var i = 0; i <= 10 ; i++) {
document.getElementById("custom-menu-item-id-" + (i + 1)).onmouseover = (function(valueOfI){ return function() {
this.style.backgroundImage= "url(images/" + backgrounds[(valueOfI % backgrounds.length)] + ".png)";
}; })(i);
document.getElementById("custom-menu-item-id-" + (i + 1)).onmouseout = function() {
this.style.background = 'none';
MenuActiveColor();
}
}
}
This surprises me. I would expect it to make all the backgrounds pink. The reason this happens is because by the time you actually hover over any of your <li> elements, i will be 10, and 10 % 4 = 2. Index #2 of your array is 'pink'.
To ensure that i is the value you want when the mouseover and mouseout events are fired, wrap them in a function.
function MenuColorChange() {
for (var i = 0; i <= 10 ; i++) {
(function(i) {
document.getElementById("custom-menu-item-id-" + (i + 1)).onmouseover = function() {
this.style.backgroundImage = "url(images/" + backgrounds[(i % backgrounds.length)] + ".png)";
}
document.getElementById("custom-menu-item-id-" + (i + 1)).onmouseout = function() {
this.style.background = 'none';
MenuActiveColor();
}
}(i));
}
}
Here is an explanation that may help: variables-in-anonymous-functions