Javascript - For loop only affecting last element in array - javascript

I'm trying to make a script that gives whatever you're pointing at (that has the class foxrainbowhover) an asynchronous rainbow effect.
I've got it working for the most part but unfortunately it, for some reason, only affects the last element inside of the array. I've ran it all through mentally several times but cannot find a single thing wrong with it. I'm hoping you'll be able to help. Here's what the effect should look like: https://jsfiddle.net/Laoderv6/
(function(){let rainbowhover = document.getElementsByClassName('foxrainbowhover');
let rainbowelements = [];
let hoverinterval = [];
let hovercounters = [];
for(let i = 0; i < rainbowhover.length; i++) {
rainbowelements[i] = spanElementContents(rainbowhover[i]);
}
//Set up the wavey effect with counters.
for(let id = 0; id < rainbowelements.length; id++) {
for(let i = 0; i < rainbowelements[id].length; i++) {
hovercounters[id] = [];
hovercounters[id][i] = 0 + i;
}
}
// Add event listeners for every item classed foxrainbowhover.
for(let id = 0; id < rainbowhover.length; id++) {
rainbowhover[id].addEventListener("mouseenter", function startanimation() {
console.log('hit');
hoverinterval[id] = setInterval(() => {
for(let i = 0; i < rainbowelements[id].length; i++) {
rainbowelements[id][i].style.color = 'hsl(' + (hovercounters[id][i] + Math.floor(i * 1)) + ', 100%, 70%';
console.log(rainbowelements[id]);
hovercounters[id][i]++;
}
}, 8);
}, false);
rainbowhover[id].addEventListener("mouseleave", function stopanimation() {
console.log('agh');
clearInterval(hoverinterval[id]);
for(let i = 0; i < rainbowelements[id].length; i++) {
rainbowelements[id][i].style.color = 'black';
}
}, false);
}
})()
function spanElementContents(element) {
let spans = [];
let chars = [];
chars.push(element.innerText.split(""));
for(let i = 0; i < chars.length; i++){
element.innerHTML = chars[i].map(function(char) {
return '<span>' + char + "</span>";
}).join('');
}
let temphtmlcollection = [].slice.call(element.children)
for(let j = 0; j < temphtmlcollection.length; j++) {
spans.push(temphtmlcollection[j]);
}
return spans;
}
body {
background-color: black;
}
h1 {
color: white;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1 class="foxrainbowhover">test1</h1>
<h1 class="foxrainbowhover">test111</h1>
<h1 class="foxrainbowhover">test111111</h1>
</body>
</html>

You are constantly resetting your array. You need to initialize it in the outer loop.
Change this:
for(let id = 0; id < rainbowelements.length; id++) {
for(let i = 0; i < rainbowelements[id].length; i++) {
hovercounters[id] = [];
hovercounters[id][i] = 0 + i;
}
}
to this:
for(let id = 0; id < rainbowelements.length; id++) {
hovercounters[id] = [];
for(let i = 0; i < rainbowelements[id].length; i++) {
hovercounters[id].push(i);
}
}
or more simply:
or (let id = 0; id < rainbowelements.length; id++) {
hovercounters[id] = rainbowelements[id].map((_, i) => i);
}
let rainbowhover = document.getElementsByClassName('foxrainbowhover');
let rainbowelements = [];
let hoverinterval = [];
let hovercounters = [];
for (let i = 0; i < rainbowhover.length; i++) {
rainbowelements[i] = spanElementContents(rainbowhover[i]);
}
//Set up the wavy effect with counters.
for (let id = 0; id < rainbowelements.length; id++) {
hovercounters[id] = rainbowelements[id].map((_, i) => i);
}
// Add event listeners for every item classed foxrainbowhover.
for(let id = 0; id < rainbowhover.length; id++) {
rainbowhover[id].addEventListener("mouseenter", function startanimation() {
hoverinterval[id] = setInterval(() => {
for(let i = 0; i < rainbowelements[id].length; i++) {
rainbowelements[id][i].style.color = 'hsl(' + (hovercounters[id][i] + Math.floor(i * 1)) + ', 100%, 70%';
hovercounters[id][i]++;
}
}, 8);
}, false);
rainbowhover[id].addEventListener("mouseleave", function stopanimation() {
clearInterval(hoverinterval[id]);
for(let i = 0; i < rainbowelements[id].length; i++) {
rainbowelements[id][i].style.color = 'black';
}
}, false);
}
function spanElementContents(element) {
let spans = [];
let chars = [];
chars.push(element.innerText.split(""));
for(let i = 0; i < chars.length; i++){
element.innerHTML = chars[i].map(function(char) {
return '<span>' + char + "</span>";
}).join('');
}
let temphtmlcollection = [].slice.call(element.children)
for(let j = 0; j < temphtmlcollection.length; j++) {
spans.push(temphtmlcollection[j]);
}
return spans;
}
h1 {
color: black;
}
<h1 class="foxrainbowhover">test1</h1>
<h1 class="foxrainbowhover">test111</h1>
<h1 class="foxrainbowhover">test111111</h1>

This is what happens when you use asynchronous functions inside a for loop. Here are a couple of ways to fix the problem:
Use let instead of var
Create a function that uses closure and returns a new function
Use a try catch or IIFE block to create a new scope
Let
for (let index = 0; index < 5; index++) {
setTimeout(() => {
console.log(index)
}, 250);
}
Function Wrapper
for (let index = 0; index < 5; index++) {
setTimeout(getFunction(index), 250);
}
function getFunction(index) {
return function() {
console.log(index);
};
}
Try Catch Block
for (let index = 0; index < 5; index++) {
try {
throw index;
} catch (index) {
setTimeout(() => {
console.log(index);
}, 250);
}
}
IIFE Block
for (let index = 0; index < 5; index++) {
(function(index) {
setTimeout(() => {
console.log(index);
}, 250);
})(index);
}

Related

Polling html elements with some

i have a ul with a nevlist id
and it's hollow then adding data(li)
I got what I needed with the for loop in the code below
but how do i do this with some not for
var newlist = document.getElementById("newlist");
function createLi(value) {
var count = 0;
for (let i = 0; i <= newlist.getElementsByTagName("li").length - 1; i++) {
if (newlist.getElementsByTagName("li")[i].getAttribute("value") == value) {
count++;
}
}
if (count==0) {
return (newlist.innerHTML += `<li class="list-group-item" value="${value}">${value}</li>`);
}
}
how can i write this otherwise
eg: with some or any

.remove is not function How to fix?

var dbRefObjectHis = firebase.database().ref('Box1').child('history');
dbRefObjectHis.on('value',gotData, errData);
function gotData(data) {
var ref = d3.selectAll('.His');
for (var i = 0; i < ref.length; i++){
ref[i].remove();
}
var history = data.val();
var keys = Object.keys(history);
for (i = 0; i < keys.length; i++) {
var k = keys[i];
var humidity = history[k].humidity;
var temperature = history[k].temperature;
$('.His').append('Humidity:' + humidity + 'Temperature:' + temperature );
}
This happens when the element you are trying to remove is not a removable Node.
try replacing
for (var i = 0; i < ref.length; i++){
ref[i].remove();
}
with
ref.forEach(function(e) {
e.remove();
});

Translate web page using javascript

I tried to translate my web page using js but my code is not working here my code
<div class="navLan">
EN
<!-- <hr> -->
RU
<!-- <hr> -->
UZ
</div>
where user select languages and i used key to give attr to the element like this
<div class="listGroup">
<a href="#row3" class="hvr-grow nav-link lang" key='about'>About</a>
Courses
<a href="#row5" class="nav-link lang" key='reg'>Registration</a>
<a href="#row6" class="nav-link lang" key='news'>News</a>
<a href="#row7" class="nav-link lang" key='feedback'>Feedback</a>
<a href="#row8" class="nav-link lang" key='contact'>Contacts</a>
<div class="hr"></div>
</div>
at the end of the code in script tag i gave translation like this
var arrLang = {
'menu-item_en': {
'about':'About',
'courses':'Courses',
'reg':'Registration',
'news':'News',
'feedback':'Feedback',
'contact':'Contacts'
},
'menu-item_ru': {
'about':'About',
'courses':'Courses',
'reg':'Registration',
'news':'News',
'feedback':'Feedback',
'contact':'Contacts'
},
'menu-item_uz': {
'about':'Biz Haqimizda',
'courses':'Kurslar',
'reg':'Ro\'yxatdan o\'tmoq',
'news':'Yangiliklar',
'feedback':'Fikr-Mulohaza',
'contact':'Aloqa'
}
}
finally my js file here
function change_language(id) {
var lang = id;
document.cookie = "lang=" + lang + ";";
var elementss = document.getElementsByClassName('lang');
var placeholders = document.getElementsByClassName('placeholders');
if (document.cookie.split(';').filter(function (item) {
return item.indexOf('lang=menu-item_en') >= 0
}).length) {
for (let i = 0; i < elementss.length; i++) {
elementss[i].innerHTML = arrLang['menu-item_en'][elementss[i].getAttribute('key')];
}
for (let g = 0; g < placeholders.length; g++){
placeholders[g].setAttribute('placeholder', arrLang['menu-item_en'][placeholders[g].getAttribute('key')]);
}
} else if (document.cookie.split(';').filter(function (item) {
return item.indexOf('lang=menu-item_uz') >= 0
}).length) {
for (let i = 0; i < elementss.length; i++) {
elementss[i].innerHTML = arrLang['menu-item_uz'][elementss[i].getAttribute('key')];
}
for (let g = 0; g < placeholders.length; g++){
placeholders[g].setAttribute('placeholder', arrLang['menu-item_uz'][placeholders[g].getAttribute('key')]);
}
} else {
for (let i = 0; i < elementss.length; i++) {
elementss[i].innerHTML = arrLang['menu-item_ru'][elementss[i].getAttribute('key')];
}
for (let g = 0; g < placeholders.length; g++){
placeholders[g].setAttribute('placeholder', arrLang['menu-item_ru'][placeholders[g].getAttribute('key')]);
}
}
};
(function () {
var elementss = document.getElementsByClassName('lang');
var placeholders = document.getElementsByClassName('placeholders');
var inputs = document.getElementsByClassName('inputs');
if (document.cookie.split(';').filter(function (item) {
return item.indexOf('lang=menu-item_en') >= 0
}).length) {
for (let i = 0; i < elementss.length; i++) {
elementss[i].innerHTML = arrLang['menu-item_en'][elementss[i].getAttribute('key')];
}
for (let g = 0; g < placeholders.length; g++){
placeholders[g].setAttribute('placeholder', arrLang['menu-item_en'][placeholders[g].getAttribute('key')]);
}
for (let j = 0; j < inputs.length; j++){
inputs[j].setAttribute('value', arrLang['menu-item_en'][inputs[j].getAttribute('key')]);
}
} else if (document.cookie.split(';').filter(function (item) {
return item.indexOf('lang=menu-item_uz') >= 0
}).length) {
for (let i = 0; i < elementss.length; i++) {
elementss[i].innerHTML = arrLang['menu-item_uz'][elementss[i].getAttribute('key')];
}
for (let g = 0; g < placeholders.length; g++){
placeholders[g].setAttribute('placeholder', arrLang['menu-item_uz'][placeholders[g].getAttribute('key')]);
}
for (let j = 0; j < inputs.length; j++){
inputs[j].setAttribute('value', arrLang['menu-item_uz'][inputs[j].getAttribute('key')]);
}
} else {
for (let i = 0; i < elementss.length; i++) {
elementss[i].innerHTML = arrLang['menu-item_ru'][elementss[i].getAttribute('key')];
}
for (let g = 0; g < placeholders.length; g++){
placeholders[g].setAttribute('placeholder', arrLang['menu-item_ru'][placeholders[g].getAttribute('key')]);
}
for (let j = 0; j < inputs.length; j++){
inputs[j].setAttribute('value', arrLang['menu-item_ru'][inputs[j].getAttribute('key')]);
}
}
})();
anyone can correct me please?
Most likely when HTML is rendering you probably don't have change_language function, so onclick="change_language(this.id)" binds anything to onclick. Let's try to add addEventListener using javascript.
Here is a working example: https://jsfiddle.net/jugrae2z/

Get index from multidimensional array

I have a multidimensional array like this:
var squares = new Array();
for(var i = 0; i <= 8; i++)
{
squares[i] = new Array();
for(var j = (i * 20) + 1; j <= 20 * i + 20; j++)
{
if (squares[i] == null)
{
squares[i] = ''+j;
}
else
{
squares[i].push('' + j);
}
}
}
I want to get the the index from the multidimensional array when I click on a square:
angular.element('.click').click(function() {
var squareId = angular.element(this).attr('id'); //Rutans id
for(var k = 0; k <= 8; k++)
{
var squareIndex = squares[k].indexOf(squareId);
}
console.log(squareIndex);
But this only results in -1 by console.log. Anyone who can help me?
Using indexOf() you are only checking that the ID exists within that array. So if it occurs in the first array, it will continue to loop over them return -1 overwriting the previous value.
What you need to do is stop the loop when you find it and return k, the index of the array you are currently iterating through.
Here is a fiddle, hope this helps
Fiddle
var squares = new Array();
for(var i = 0; i <= 8; i++)
{
squares[i] = new Array();
for(var j = (i * 20) + 1; j <= 20 * i + 20; j++)
{
if (squares[i] == null)
{
squares[i] = ''+j;
}
else
{
squares[i].push('' + j);
}
}
}
console.log(squares);
$('a').on('click', function(){
var squareId = $(this).attr('id');
var squareIndex = 0,
numberIndex = 0;
for(var k = 0; k < squares.length; k++)
{
squareIndex = squares[k].indexOf(squareId);
if (squareIndex > -1) {
numberIndex = squareIndex;
squareIndex = k;
break
}
}
alert('NumberIndex: '+ numberIndex+' ParentSquareIndex: '+ squareIndex);
});
please see here http://plnkr.co/edit/aldjCQRchgESR7IWn367?p=preview i hope that will help.
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.2.x" src="https://code.angularjs.org/1.2.22/angular.js" data-semver="1.2.22"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello !</p>
<table>
<tr ng-repeat="lines in squares track by $index ">
<td ng-repeat="nr in lines track by $index" ng-click="getMyId(nr)">{{nr}}</td>
</tr>
</table>
</body>
</html>
JS:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
var squares = [];
for(var i = 0; i <= 8; i++)
{
squares[i] = [];
for(var j = (i * 20) + 1; j <= 20 * i + 20; j++)
{
if (squares[i] === null)
{
squares[i] = ''+j;
}
else
{
squares[i].push('' + j);
}
}
}
$scope.squares = squares;
$scope.getMyId = function(id){
alert(id);
}
console.log(squares);
});

Neural network in Javascript not learning properly

I've tried to rewrite neural network found here to javascript. My javascript code looks like this.
function NeuralFactor(weight) {
var self = this;
this.weight = weight;
this.delta = 0;
}
function Sigmoid(value) {
return 1 / (1 + Math.exp(-value));
}
function Neuron(isInput) {
var self = this;
this.pulse = function() {
self.output = 0;
self.input.forEach(function(item) {
self.output += item.signal.output * item.factor.weight;
});
self.output += self.bias.weight;
self.output = Sigmoid(self.output);
};
this.bias = new NeuralFactor(isInput ? 0 : Math.random());
this.error = 0;
this.input = [];
this.output = 0;
this.findInput = function(signal) {
var input = self.input.filter(function(input) {
return signal == input.signal;
})[0];
return input;
};
}
function NeuralLayer() {
var self = this;
this.pulse = function() {
self.neurons.forEach(function(neuron) {
neuron.pulse();
});
};
this.neurons = [];
this.train = function(learningRate) {
self.neurons.forEach(function(neuron) {
neuron.bias.weight += neuron.bias.delta * learningRate;
neuron.bias.delta = 0;
neuron.input.forEach(function(input) {
input.factor.weight += input.factor.delta * learningRate;
input.factor.delta = 0;
})
})
}
}
function NeuralNet(inputCount, hiddenCount, outputCount) {
var self = this;
this.inputLayer = new NeuralLayer();
this.hiddenLayer = new NeuralLayer();
this.outputLayer = new NeuralLayer();
this.learningRate = 0.5;
for(var i = 0; i < inputCount; i++)
self.inputLayer.neurons.push(new Neuron(true));
for(var i = 0; i < hiddenCount; i++)
self.hiddenLayer.neurons.push(new Neuron());
for(var i = 0; i < outputCount; i++)
self.outputLayer.neurons.push(new Neuron());
for (var i = 0; i < hiddenCount; i++)
for (var j = 0; j < inputCount; j++)
self.hiddenLayer.neurons[i].input.push({
signal: self.inputLayer.neurons[j],
factor: new NeuralFactor(Math.random())
});
for (var i = 0; i < outputCount; i++)
for (var j = 0; j < hiddenCount; j++)
self.outputLayer.neurons[i].input.push({
signal: self.hiddenLayer.neurons[j],
factor: new NeuralFactor(Math.random())
});
this.pulse = function() {
self.hiddenLayer.pulse();
self.outputLayer.pulse();
};
this.backPropagation = function(desiredResults) {
for(var i = 0; i < self.outputLayer.neurons.length; i++) {
var outputNeuron = self.outputLayer.neurons[i];
var output = outputNeuron.output;
outputNeuron.error = (desiredResults[i] - output) * output * (1.0 - output);
}
for(var i = 0; i < self.hiddenLayer.neurons.length; i++) {
var hiddenNeuron = self.hiddenLayer.neurons[i];
var error = 0;
for(var j = 0; j < self.outputLayer.neurons.length; j++) {
var outputNeuron = self.outputLayer.neurons[j];
error += outputNeuron.error * outputNeuron.findInput(hiddenNeuron).factor.weight * hiddenNeuron.output * (1.0 - hiddenNeuron.output);
}
hiddenNeuron.error = error;
}
for(var j = 0; j < self.outputLayer.neurons.length; j++) {
var outputNeuron = self.outputLayer.neurons[j];
for(var i = 0; i < self.hiddenLayer.neurons.length; i++) {
var hiddenNeuron = self.hiddenLayer.neurons[i];
outputNeuron.findInput(hiddenNeuron).factor.delta += outputNeuron.error * hiddenNeuron.output;
}
outputNeuron.bias.delta += outputNeuron.error * outputNeuron.bias.weight;
}
for(var j = 0; j < self.hiddenLayer.neurons.length; j++) {
var hiddenNeuron = self.hiddenLayer.neurons[j];
for(var i = 0; i < self.inputLayer.neurons.length; i++) {
var inputNeuron = self.inputLayer.neurons[i];
hiddenNeuron.findInput(inputNeuron).factor.delta += hiddenNeuron.error * inputNeuron.output;
}
hiddenNeuron.bias.delta += hiddenNeuron.error * hiddenNeuron.bias.weight;
}
};
this.train = function(input, desiredResults) {
for(var i = 0; i < self.inputLayer.neurons.length; i++) {
var neuron = self.inputLayer.neurons[i];
neuron.output = input[i];
}
self.pulse();
self.backPropagation(desiredResults);
self.hiddenLayer.train(self.learningRate);
self.outputLayer.train(self.learningRate);
};
}
Now I'm trying to learn it how to resolve XOR problem. I'm teaching it like this:
var net = new NeuralNet(2,2,1);
var testInputs = [[0,0], [0,1], [1,0], [1,1]];
var testOutputs = [[1],[0],[0],[1]];
for (var i = 0; i < 1000; i++)
for(var j = 0; j < 4; j++)
net.train(testInputs[j], testOutputs[j]);
function UseNet(a, b) {
net.inputLayer.neurons[0].output = a;
net.inputLayer.neurons[1].output = b;
net.pulse();
return net.outputLayer.neurons[0].output;
}
The problem is that all results that I get is close to 0.5 and pretty random, no matter what arguments I use. For example:
UseNet(0,0) => 0.5107701166677714
UseNet(0,1) => 0.4801498747476413
UseNet(1,0) => 0.5142463167153447
UseNet(1,1) => 0.4881829364416052
What can be wrong with my code?
This network is big enough for the XOR problem and I can't see any obvious mistakes, so I suspect it's getting stuck in a local minimum.
Try going through the training set 10,000 times instead of 1000; this gives it a better chance of breaking out of any minima and converging. You can also increase convergence a lot by upping the number of hidden neurons, tweaking η (the learning rate) or adding momentum. To implement the latter, try using this as your training function:
this.train = function(learningRate) {
var momentum = 0 /* Some value, probably fairly small. */;
self.neurons.forEach(function(neuron) {
neuron.bias.weight += neuron.bias.delta * learningRate;
neuron.bias.delta = 0;
neuron.input.forEach(function(input) {
input.factor.weight += (input.factor.delta * learningRate) + (input.factor.weight * momentum);
input.factor.delta = 0;
})
})
}
I've had good results changing the learning rate to 1.5 (which is pretty high) and momentum to 0.000001 (which is pretty small).
(Incidentally, have you tried running the .NET implementation with a few different seeds? It can take quite a while to converge too!)
This system uses fuzzy logic. As it says in the article don't use integers instead use "close" real numbers as the article suggests -- try
UseNet(0.1,0.1) =>
UseNet(0.1,0.9) =>
UseNet(0.9,0.1) =>
UseNet(0.9,0.9) =>
For the results anything above 0.5 is a 1 and below is 0
Hmmmm
Try instead of:
var testInputs = [[0,0], [0,1], [1,0], [1,1]];
var testOutputs = [[1],[0],[0],[1]];
This:
var testInputs = [[0.05,0.05], [0.05,0.95], [0.95,0.05], [0.95,0.95]];
var testOutputs = [[1],[0],[0],[1]];
or
var testInputs = [[0,0], [0,1], [1,0], [1,1]];
var testOutputs = [[0.95],[0.05],[0.05],[0.95]];

Categories

Resources