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
Related
I'm trying to build a visual representation of some famous sorting algorithms in javascript, but I can't understand why my code doesn't print each iteration even if the print function is in the for loop. I only get the final result.
This is the sorting function, in particular the selection sort algorithm:
function selectionSort(array) {
var i, j, min_idx;
let n = array.length;
for (i = 0; i < n-1; i++)
{
min_idx = i;
for (j = i + 1; j < n; j++)
{
if (array[j] < array[min_idx])
{
min_idx = j;
}
}
var temp = array[min_idx];
array[min_idx] = array[i];
array[i] = temp;
printArray(array);
}
}
And this is the printing function:
function printArray(array) {
document.getElementById('container').innerHTML ='';
for(let i = 0; i < array.length; i++)
{
document.getElementById('container').innerHTML += '<div class = "column '+i+'" id = "'+i+'" style = "height: '+array[i]+'px;"></div>';
}
}
Thank you a lot
It's what #Bravo states in the comments. The screen is updates at least 60 times per second, but it takes less time to do the sorting. So you need to add a timeout in a recursive loop so you can actually see the animation.
I replaced the first for loop with this recursive loop. I think the code it self-explanatory.
I did some optimization in your printArray(), where it takes time to constantly doing DOM changes. Instead, loop through to create a text string and then add it once to #container.innerHTML. There were also some faulty thinking in the value that you gave the visualized divs, where you only added the order (i), instead of adding the actual value (array[i]).
const iterationLegend = document.getElementById('iterations');
const containerDiv = document.getElementById('container');
const ANIMATION_SPEED = 1000;
const RESTART = 0;
var firstIteration;
function startSelectionSort(array) {
firstIteration = RESTART;
selectionSort(array);
}
function selectionSort(array) {
let min_idx = firstIteration,
n = array.length;
for (let j = firstIteration + 1; j < n; j++) {
if (array[j] < array[min_idx]) {
min_idx = j;
}
}
var temp = array[min_idx];
array[min_idx] = array[firstIteration];
array[firstIteration] = temp;
visualizeArray(array);
iterationLegend.textContent = 'iteration ' + firstIteration;
if (firstIteration < n - 1) {
firstIteration++;
setTimeout(selectionSort.bind(this, array), ANIMATION_SPEED);
} else {
iterationLegend.textContent = 'Done';
}
}
function visualizeArray(array) {
let elementStr = '';
let value = 0;
for (let i = 0; i < array.length; i++) {
value = array[i];
elementStr += `<div class="column${value}" data-value="${value}"></div>`;
}
containerDiv.innerHTML = elementStr;
}
startSelectionSort([2, 3, 5, 5, 1, 1, 1, 1, 4]);
fieldset {
display: inline;
}
#iterations {
font-size: 13px;
text-transform: uppercase;
}
#container {
display: inline-flex;
}
#container > div {
width: 10px;
height: 100px;
margin: 2px 1px 0px;
}
.column1 {
background-color: brown;
}
.column2 {
background-color: black;
}
.column3 {
background-color: teal;
}
.column4 {
background-color: red;
}
.column5 {
background-color: indigo;
}
<fieldset>
<legend id="iterations">Iterations</legend>
<div id="container"></div>
</fieldset>
I am attempting to create a grid that contains one letter in each box (like a Word Find puzzle).
I have successfully created a grid that shows w/ the determined number of cols/rows, but when I attempt to put one letter in each box, I get the following ten times in each box instead of a single letter:
[object
Object]
Here is the JavaScript:
$(function() {
var letters = [
'rzeabppssgcddrvddydtjrkei', // 1
'cezcqubhniittonieqerbiuvm', // 2
'jqcjnasionsncvbsrwtabddsu', // 3
'olselesitneagittrjanreinv', // 4
'nqnaisdenmeibvurellsnrioc', // 5
'ydnlevrnyeaidrwifkufmsuis', // 6
'dcccjeeaogsemudbeemefaptn', // 7
'evonsqpdepislsnudnurwjbpo', // 8
'grytiunnafsexattmtclaimoi', // 9
'pnqrhocbiieeinoitacilppat', // 10
];
var letter = [];
function splitRows(arr, arr2) {
for (let i=0; i < arr.length; i++) {
arr[i].split();
for (let j=0; j < arr.length; j++) {
arr2[j] = arr[i][j];
}
}
}
splitRows(letters, letter);
function* gen(arr) {
for(i=0; i < arr.length; i++) {
yield arr[i];
}
}
function generateGrid(rows, cols, arr) {
var grid = "<table>";
for(row = 1; row <= rows; row++) {
grid += "<tr>";
for(col = 1; col <= cols; col++) {
grid += "<td>";
for(let i=0; i < arr.length; i++) {
grid += gen(arr).next(); // not sure if the .next() generator works yet
}
grid += "</td>"; // 'letters' needs to input the next letter in letters each time it is called
}
grid += "</tr>";
}
return grid;
}
$("#tableContainer").append(generateGrid(26, 22, letter));
});
The first function is intended to take rows and split them into singular letters (eventually taking rows as an input, but for testing purposes I have them in an array)
The second function is a generator to insert into the generateGrid() function that is used to generate the next letter in the sequence each time a box is created.
You should convert your string data to a matrix first then you can run the matrix through a table.
The following jQuery plugin clears the table and replaces it with rows and columns based on the data.
Note: I also added in tag name validation, in the case where the element the plugin was being invoked upon was not a <table> element.
var DEBUG_EXPERIMENTAL = false;
initializePlugins(); // Forward Declaration of jQuery plugins
let rawStringData = `
rzeabppssgcddrvddydtjrkei
cezcqubhniittonieqerbiuvm
jqcjnasionsncvbsrwtabddsu
olselesitneagittrjanreinv
nqnaisdenmeibvurellsnrioc
ydnlevrnyeaidrwifkufmsuis
dcccjeeaogsemudbeemefaptn
evonsqpdepislsnudnurwjbpo
grytiunnafsexattmtclaimoi
pnqrhocbiieeinoitacilppat
`;
$('.word-search').buildWordSearch(rawStringData, 'letter');
$('.letter').enableHighliting('highlight');
function initializePlugins() {
(($) => {
$.stringToMatrix = function(str) {
return str.trim().split('\n').map(row => row.trim().split(''));
};
$.fn.buildWordSearch = function(stringData, cellClass) {
this.throwErrorIfNotType('TABLE');
return this.append($('<tbody>')
.append($.stringToMatrix(stringData).map(row => {
return $('<tr>').append(row.map(col => {
return $('<td>').addClass(cellClass).text(col);
}));
})));
};
$.fn.throwErrorIfNotType = function(expectedTagName) {
let actualTagName = this.prop('tagName');
if (actualTagName !== expectedTagName) {
throw Error(`Element '${actualTagName}' is not a '${expectedTagName}'!`);
}
};
$.fn.getCell = function(x, y) {
return this.find(`tr:nth-child(${y + 1}) td:nth-child(${x + 1})`);
};
$.fn.enableHighliting = function(cls) {
return this.each(() => {
this.on({
mouseover: function() {
let $table = $(this).closest('table');
let $row = $(this).closest('tr');
let rowIndex = $row.index();
let colIndex = $(this).index();
let rowCount = $table.find('tbody tr').length;
let colCount = $row.find('td').length;
// Hightlights diagonals.
if (DEBUG_EXPERIMENTAL) {
let limit = rowCount;
let xNeg = colIndex - 1;
let xPos = colIndex + 1;
let yNeg = rowIndex - 1;
let yPos = rowIndex + 1;
while (limit > 0) {
if (xNeg > -1 && yNeg > -1) {
$table.getCell(xNeg, yNeg).addClass(cls);
}
if (xPos < colCount && yNeg > -1) {
$table.getCell(xPos, yNeg).addClass(cls);
}
if (xNeg > -1 && yPos < rowCount) {
$table.getCell(xNeg, yPos).addClass(cls);
}
if (xPos < colCount && yPos < rowCount) {
$table.getCell(xPos, yPos).addClass(cls);
}
xNeg--;
xPos++;
yNeg--;
yPos++;
limit--;
}
}
$row.addClass(cls);
$table.find(`td:nth-child(${colIndex + 1})`).addClass(cls);
},
mouseout: function() {
let $table = $(this).closest('table');
let $row = $(this).closest('tr');
let rowIndex = $row.index();
let colIndex = $(this).index();
let rowCount = $table.find('tbody tr').length;
let colCount = $row.find('td').length;
// Un-hightlights diagonals.
if (DEBUG_EXPERIMENTAL) {
let limit = rowCount;
let xNeg = colIndex - 1;
let xPos = colIndex + 1;
let yNeg = rowIndex - 1;
let yPos = rowIndex + 1;
while (limit > 0) {
if (xNeg > -1 && yNeg > -1) {
$table.getCell(xNeg, yNeg).removeClass(cls);
}
if (xPos < colCount && yNeg > -1) {
$table.getCell(xPos, yNeg).removeClass(cls);
}
if (xNeg > -1 && yPos < rowCount) {
$table.getCell(xNeg, yPos).removeClass(cls);
}
if (xPos < colCount && yPos < rowCount) {
$table.getCell(xPos, yPos).removeClass(cls);
}
xNeg--;
xPos++;
yNeg--;
yPos++;
limit--;
}
}
$row.removeClass(cls);
$table.find(`td:nth-child(${colIndex + 1})`).removeClass(cls);
}
});
});
};
})(jQuery);
}
.word-search {
border: 2px solid #000;
border-collapse: collapse;
}
.word-search td {
width: 1.25em;
height: 1.25em;
line-height: 1.25em;
text-align: center;
}
.highlight {
background: #FFD;
}
.letter.highlight:hover {
background: #FF0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="word-search"></table>
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);
}
Currently my code iterates through each <li> within a <td> cell and applies a class to the <li>. I've now added <a> tags in between each <li> and am having problems accessing the <a>. I essentially want to add a class to each <a> tag rather than the <li>.
HTML
<td style='padding: 0;' bgcolor='#FAFAFA'>
<ul class='doctorList'>
<li id='1'><a style='text-decoration: none;'>Curly</a></li>
<li id='2'>Larry</li>
<li id='3'>Moe</li>
</ul>
</td>
JavaScript
function mapBookedAppointmentsToCalendar()
{
var bookedAppointmentsArray = <?php echo json_encode($mappingIdArray) ?>;
var table = document.getElementById("tbl_calendar");
for (var i = 0, row; row = table.rows[i]; i++) {
for (var j = 0, col; col = row.cells[j]; j++) {
var li = col.querySelectorAll("li");
for (var k = 0; k < li.length; k++) {
for (var a = 0; a < bookedAppointmentsArray.length; a++)
{
if (li[k].id == bookedAppointmentsArray[a])
{
li[k].className = "colorRed booked";
break;
} else
{
li[k].className = "colorGreen";
}
}
}
}
}
}
Did you try using the query selector to find those <a> ?
var li = col.querySelectorAll("#tbl_calendar li a");
for (var k = 0; k < li.length; k++) {
for (var a = 0; a < bookedAppointmentsArray.length; a++)
{
if (li[k].id == bookedAppointmentsArray[a])
{
li[k].className = "colorRed booked";
break;
} else
{
li[k].className = "colorGreen";
}
}
}
You don't need to use table to access it. Just keep in mind getElementsByClassName method:
u = document.getElementsByClassName('doctorList');
for (i = 0; i < u.length; i++){
l = u[i].getElementsByTagName('li');
for (j = 0; j < l.length; j++){
l[j].className = 'red';
}
}
Checkout this demo
If you don't need ancient browsers support, you can do this:
var ul = document.querySelector('ul.doctorList');
var li = ul.querySelectorAll('li');
// convert the node list to an array
li = [].slice.call(li);
li.forEach(function(element) {
if (element.id === '1') {
var a = element.querySelector('a');
a.className = 'red';
}
});
var ul = document.querySelector('ul.doctorList');
var li = ul.querySelectorAll('li');
// convert the node list to an array
li = [].slice.call(li);
li.forEach(function(element) {
if (element.id === '1') {
var a = element.querySelector('a');
a.className = 'red';
}
});
.red {
color: red;
}
<td style='padding: 0;' bgcolor='#FAFAFA'>
<ul class='doctorList'>
<li id='1'><a style='text-decoration: none;'>Curly</a></li>
<li id='2'>Larry</li>
<li id='3'><a style='text-decoration: none;'>Moe</a></li>
</ul>
</td>
I'm newbie with JavaScript, so I decided to develop a little application which is supposed to show the schedule of the streetcar of the place I live, because of the lack of the information on the official webpage.
I have several arrays with the starting time of the line, and as the time to reach each station it's the same, I only have to add the total minutes to the first hour.
There's a form for the user to set a range of hours. So, my main problem is that the "adder();" function is supposed to iterate and print all the values from an array. Instead of doing that, it takes always the same index, 24, so if the array returned has less than 24 indexes, it does not work.
Here's the HTML:
< input type="button" class="submit" value="Enviar" onclick="caller()"/>
JavaScript:
function cropHours(i){
if (i.substr(0,2) >= hora1user_recortada && i.substr(0,2) <= hora2user_recortada) {
horas.push(i);
}
return horas;
}
function adder() {
minInicio1 = horas[i].substr(0,2);
minInicio2 = horas[i].substr(3,2);
document.getElementById("test4").innerHTML = "---" + minInicio1+"_"+minInicio2;
y = parseInt(total) + parseInt(minInicio2);
document.getElementById("test5").innerHTML = "total vale "+total+"minInicio1 vale "+minInicio1+"... minInicio2 vale "+minInicio2+"...Y vale "+y;
html += "<td>"+y+"</td>";
document.getElementById("horario").innerHTML = html;
}
This is a part of another function:
if (platform == 1) {
for (var j = 0; j <= indexorigen; j++) {
total += mins1[j];
}
for (var j = 0; j <= indexdestino; j++) {
total2 += mins1[j];
}
if (today !== "Sábado" || today !== "Domingo") {
for each (var i in horainiciolaboral1) {
cropHours(i);
//adder(horainiciolaboral1);
}
} else {
for each (var i in horainiciofinde1) {
cropHours(i);
}
}
} else {
for (var x = 0; x <= indexorigen; x++) {
total += mins2[x];
}
for (var x = 0; x <= indexdestino; x++) {
total2 += mins2[x];
}
if (today !== "Sábado" || today !== "Domingo") {
for each (var i in horainiciolaboral2) {
cropHours(i);
}
} else {
for each (var i in horainiciofinde2) {
cropHours(i);
}
}
}
/*for (var i = 0; i <= horainiciolaboral1.length; i++) {
adder(horainiciolaboral1);
}*/
//horario = horas.slice(11);
for each (var i in horas) {
adder();
}
document.getElementById("test6").innerHTML = horas;
document.getElementById("test3").innerHTML = total + "----" + total2;
// ******************************************
// ** FUNCTION WHICH CALLS EVERY FUNCTION **
// ******************************************
// STARTS
function caller() {
cleaner();
retrieve_origen();
retrieve_destino();
getIndex();
sumMinutes();
getHours();
}
This is the problem:
for each (var i in horas) {
adder();
}
Thank you in advance.
Pass i to adder() as an argument:
adder(i);
...and define it as a parameter in the function:
function adder( i ) {
//...