does anybody know how to reiterate through only the first 5 elements using jQuery's each?
$(".kltat").each(function() {
// Only do it for the first 5 elements of .kltat class
}
From the documentation:
We can break the $.each() loop at a particular iteration by making the callback function return false.
Furthermore, the same documentation says of the callback you give to .each:
In the case of an array, the callback is passed an array index and a corresponding array value each time.
So try something like this:
$(".kltat").each(function(index, element) {
// do something
// ...
return index < 4;
});
So after you execute the loop on the fifth time (index will equal 4), the loop will stop. Note that using this n-1 logic is needed because you execute the body of the loop before you evaluate the breaking condition.
$(".kltat").each(function(index, element) {
$(element).css('color', 'red');
return index < 4;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="kltat">Item 1</li>
<li class="kltat">Item 2</li>
<li class="kltat">Item 3</li>
<li class="kltat">Item 4</li>
<li class="kltat">Item 5</li>
<li class="kltat">Item 6</li>
<li class="kltat">Item 7</li>
</ul>
You can implement a counter such as this:
var counter = 1;
$(".kltat").each(function() {
// Only do it for the first 5 elements of .kltat class
if (counter==5) {
return false;
} else {
counter++;
}
}
or something of this sort.
How about using .filter():
$(".kltat").filter(function (i) { return i < 5; })
.each(function () {
// ...
});
$(".kltat").slice(0,5).each(function() {
// Only do it for the first 5 elements of .kltat class
})
And without jquery:
[].slice.call(document.querySelectorAll('.kltat')).slice(0,5).forEach(function (element) {
doStuff(element)
})
Related
I have a HTML code with 3 list items and the ids for my ul is 'exercise6-list'
<ul id="exercise6-list">
<li>List 1</li>
<li>List 2</li>
<li>List 3</li>
</ul>
I need to make each li glow for three seconds and repeat itself
So far I have written:
var moveGlow = function() {
var element = document.querySelector("#exercise6-list");
// ... to make it glow i've so far used .setAttribute("class", "glow")
};
clearInterval(window.interval);
window.interval = setInterval(moveGlow, 3000);
*I'm very new to programming, but thank you for your help
To make a timed function we use setInterval, and add the class "glow" to the current element, and remove that class from the previous one.
To cycle through the elements, we use an index-variable, which increases per cycle and loops back around when necessary.
let index = 0;
let elements = document.querySelector("#exercise6-list").children;
let glowFunc = () => {
if (elements.length <= 0) { // Actually not needed since we know there are 3 elements
index = 0;
return;
}
index %= elements.length; // Map index to valid values
elements[(elements.length + index - 1) % elements.length].classList.remove("glow"); // Remove "glow" from previous element
elements[index].classList.add("glow"); // Add "glow" to current element
++index; // Increase 'index'
};
glowFunc(); // Initial call to "start" it without initial delay
setInterval(glowFunc, 3000); // Make it a timed function
li {transition: background-color 0.2s}
.glow {background-color: orange}
<ul id="exercise6-list">
<li>List 1</li>
<li>List 2</li>
<li>List 3</li>
</ul>
Array.from(element.children).forEach(child => {
child.classList.add('glow');
setTimeout(() => child.classList.remove('class'), 3000);
});
However, I think weird things will happen if you make each li glow for longer than the interval, which you have currently set to 300.
If you use something like jQuery you don't need to iterate manually.
Here is an recursive solution with async await.
var moveGlow = async function() {
var element = document.querySelector(".box");
element.style.background = "green";
await sleep(3000)
element.style.background = "red"
await sleep(3000);
return moveGlow()
}
let sleep = (time) => new Promise(res => setTimeout(res, time))
moveGlow()
.box {
width: 100px;
height: 100px;
background: red;
}
<div class="box">
</div>
Instead of setInterval I used setTimeout since interval keeps running until you stop it, where as timeout only happens once then you have to rerun it.
This code is a recursive function that uses a counter to determine where in the list the loop is currently at.
var parent = document.querySelector("#exercise6-list");
var children = parent.querySelectorAll("li");
var total = children.length;
function glow(counter) {
children.forEach(function(el) {
el.classList.remove("highlight");
});
el = children[counter];
el.classList.add("highlight");
setTimeout(function() {
if (counter < total - 1) {
counter++;
glow(counter);
}
else{
el.classList.remove("highlight");
}
}, 3000);
}
glow(0);
.highlight {
background: red;
color: #fff
}
<ul id="exercise6-list">
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
var d=document.querySelector("#exercise6-list");
d.style="background-color:yellow;"
setTimeout(()=>{
d.style=""
},3000)
//time is measured in milliseconds.. simple math
<div style="background-color:yellow" id="exercise6-list">
<li>Text 1</li>
<li>Text 2</li>
<li>Text 3</li>
</div>
I have an array and I want to be able to divide it in 2 components, so like the first 5 elements go in one element and whatever is left go in the second element. I know I have to use slice and I can get the first component but not sure about the second one.
I have something like this:
if (item.children) {
return item.children.slice(0, 5).map((childItem) => {
const navItem = (
<Link activeClassName={styles.active} to={childItem.url}>{childItem.text}</Link>
)
return (
<li key={childItem.id}>
{navItem}
</li>
)
})
}
So how do I get another component to appear after, like
<li key={childItem.id}>
{navItem}
</li>
{navExtra}
that contains all the remaining elements from the array?
The final html should look something like this:
<ul>
<!-- // first five elements of the array -->
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<!-- // new component -->
<li>
<button>Extra</button>
<ul>
<!-- // remaning elements of the array -->
<li>Item 6</li>
<li>Item 7</li>
<!-- // etc -->
</ul>
</li>
</ul>
Variables will really help your code readability here. slice(beginIndex, endIndex) and slice(begin) are the keys.
You already know slice(0,5) will get you the first half of the array.
var x = slice(5) will get you the components of the array from the fifth element to the end. You can call map() and do any other processing on these elements to get something to display.
MSDN docs for slice
You can create an HTML element with appendChild. Here is an example of how you could do what you are trying to do:
<!DOCTYPE html>
<html>
<body>
<div id="div1">
</div>
<script>
var array = ["this", "is", "a", "random", "array", "that", "i", "just", "made"];
var splitBy = Math.round(array.length / 2);
//for first half
for (var i = 0; i <= splitBy; i++){
var li = document.createElement("li");
var node = document.createTextNode(array[i]);
li.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(li);
}
//for second half
for (var i = splitBy + 1; i < array.length; i++){
var li = document.createElement("li");
var node = document.createTextNode(array[i]);
li.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(li);
}
</script>
</body>
</html>
Hope this helps!
When you use splice, it alters the original array, essentially leaving you item.children with all of the elements you want to include in navExtra
We can create a return object that holds navItems and navExtra separately for you to render separately, adding the wrapping <ul> in the render, etc.
if (item.children) {
let ret = {
navItems: [],
navExtra: []
};
navItems = item.children.splice(0, 5);
ret.navItems.push(
navItems.map(navItem => {
return (
<li key={navItem.id}>
<Link activeClassName={styles.active} to={navItem.url}>{navItem.text}</Link>
</li>
)
})
)
ret.navExtra.push(
item.children.map(navExtra => {
<li key={navExtra.id}>
<Link activeClassName={styles.active} to={navExtra.url}>{navExtra.text}</Link>
</li>
})
)
}
I have a bulletted list like this:
<ol>
<li>Point 1</li>
<li>Point 2</li>
<li>Point 3 has sub-points
<ul>
<li>Sub-point about something</li>
<li>Sub-point about something else</li>
</ul>
</li>
</ol>
I am transliterating from one writing script to another writing script, so I have to run something against the text in each tag. Here is what my jQuery looks like:
$("li").each(function() {
text = dev2latin($(this).text());
}
It makes it look like this:
Point 1
Point 2
Point 3 has sub-points Sub-point about something
Sub-point about something else
I have tried several iterations of jQuery selectors including ol>li, etc, but none of them give the desired result. Thoughts?
The problem is calling .text() in the parent li will return the text content of the child li also
$("li").contents().each(function () {
if (this.nodeType == 3 && this.nodeValue.trim()) {
this.nodeValue = dev2latin(this.nodeValue)
}
})
Demo: Fiddle
You can fetch text nodes using .contents(), then you can .filter() them and perform desired operation.
$(document).ready(function() {
$("li")
.contents()
.filter(function() {
return this.nodeType == 3;
}) //Filter text nodes
.each(function() {
this.nodeValue = dev2latin(this.nodeValue); //You can also textContent
});
});
Here is an example:
$(document).ready(function() {
$("li").contents().filter(function() {
return this.nodeType == 3;
}).each(function() {
this.textContent = this.textContent + 'Updated';
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol>
<li>Point 1</li>
<li>Point 2</li>
<li>Point 3 has sub-points
<ul>
<li>Sub-point about something</li>
<li>Sub-point about something else</li>
</ul>
</li>
</ol>
$('ol > li').each(function(){ console.log($(this)[0].childNodes[0]); });
$('ul > li').each(function(){ console.log($(this)[0].childNodes[0]); });
Try this way.
I have a set of list items that contain nested lists, sort of like this:
<ul class="searchselectors">
<li class="group">Group name 1
<ul>
<li class="item selected">List item 1.1</li>
<li class="item">List item 1.2</li>
<li class="item">List item 1.3</li>
</ul>
</li>
<li class="group">Group name 2
<ul>
<li class="item">List item 2.1</li>
<li class="item">List item 2.2</li>
<li class="item">List item 2.3</li>
</ul>
</li>
<li class="group">Group name 3
<ul>
<li class="item">List item 3.1</li>
</ul>
</li>
</ul>
I want to cycle through all of the .item elements using up/down arrow keys (which I already have set up by using on('keydown') and catching key codes 38 and 40) and set .selected on the next item before or after the currently selected item, wrapping around to the top/bottom as necessary.
Using $().next() and $().prev() will not work, since it will only work on siblings, and not on a jQuery object such as $('.searchselectors .item').\
I was working on the same problem but in my project I'm using KnockoutJS. In fact, the original logic was written with pure jQuery and I refactored it with Knockout. Here's a solution for your problem using jQuery:
Fiddle - http://jsfiddle.net/6QN77/2/
I didn't spend too much time cleaning up the JavaScript, but I'm leaving that to you now.
HTML
<ul id="searchselectors">
<li class="group">Group name 1
<ul>
<li class="item selected">List item 1.1</li>
<li class="item">List item 1.2</li>
<li class="item">List item 1.3</li>
</ul>
</li>
<li class="group">Group name 2
<ul>
<li class="item">List item 2.1</li>
<li class="item">List item 2.2</li>
<li class="item">List item 2.3</li>
</ul>
</li>
<li class="group">Group name 3
<ul>
<li class="item">List item 3.1</li>
</ul>
</li>
</ul>
jQuery
$(function () {
var $menu = $("#searchselectors"),
$items = $menu.find(".item"),
$selectedItem = $menu.find(".selected"),
selectedIndex = $selectedItem.length - 1;
$(document).on("keydown", function (e) {
switch(e.keyCode) {
case 40: // down arrow
$selectedItem.removeClass("selected");
selectedIndex = (selectedIndex + 1) % $items.length;
$selectedItem = $items.eq(selectedIndex).addClass("selected");
break;
case 38: // up arrow
$selectedItem.removeClass("selected");
selectedIndex = (selectedIndex - 1) % $items.length;
$selectedItem = $items.eq(selectedIndex).addClass("selected");
break;
}
});
});
UPDATE: My solution revolves around getting a reference to a wrapper element (#searchselectors) and getting all the LI elements marked with the CSS class .item. Next I get a reference to the currently selected element and its index. Finally, the code listens to the down and up arrow keys being pressed (keydown), decrementing if going up and incrementing if going up. Cycling is achieved via the modulus operator. The selected item's CSS class is removed and put back. The selected item reference is used for performance reasons so I don't have to write $items.removeClass(".selected").eq(selectedIndex).addClass("selected");
In my quest to provide native JS answers to those looking for it, here is #Mario j Vargas' good answer adapted in native Javascript. It only takes 2 lines of extra code.
http://jsfiddle.net/kevinvanlierde/7tQSW/2/
Only putting the JS up here, HTML is the same.
(function () {
var $menu = document.getElementById('searchselectors'),
items = $menu.getElementsByClassName('item'),
$selectedItem = $menu.getElementsByClassName('selected')[0],
selectedIndex = Array.prototype.indexOf.call($selectedItem, items)+1;
document.body.addEventListener('keydown', function (e) {
switch(e.keyCode) {
case 40: // down arrow
$selectedItem.className = $selectedItem.className.replace(' selected','');
selectedIndex = selectedIndex < items.length - 1 ? selectedIndex + 1 : selectedIndex;
$selectedItem = items[selectedIndex];
$selectedItem.className += ' selected';
break;
case 38: // up arrow
$selectedItem.className = $selectedItem.className.replace(' selected','');
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : selectedIndex;
$selectedItem = items[selectedIndex];
$selectedItem.className += ' selected';
break;
}
}, false);
}());
Easiest way to get all the list items with class "item" is:
var items = $('.item');
for (var i = 0; i < items.length; i++) {
var item = items[i]; // iterate
}
And then, you can select the next item from the list
OR
you can do this
if (!$().next) {
var nextUL= $().parent.find('ul')
iterateThruList(nextUL);
}
You could use something like
var UL = $(".searchselectors").children().length; //number of UL (group names)
to iterate through items.
I have a fiddle here: http://jsfiddle.net/justinboyd101/4nrbb/
Here is my question:
Why are my console.log function and my statement to add html to a div working, while it's not running on my other looping jQuery function?
For more details, please read below:
I'm trying to create a news ticker using setInterval. The animation is supposed to slide text in from the right side of the screen, then push the content down, then reset back to its original position. For some reason it will only run animations once. I've set up a simple function where ever interval will gather information from the array and add it to an empty div.
Here is my code if you do not wish to go to jsfiddle:
HTML
<div id="newsValueText" class="newsValueText floatLeft darkBlue">
<ul id="newsTicker" class="newsTicker">
<li name="tick" ph="tick1">We have in-store technical support.</li>
<li name="tick" ph="tick2">Option 2</li>
<li name="tick" ph="tick3">Option 3</li>
<li name="tick" ph="tick4">Option 4</li>
<li name="tick" ph="tick5">Option 5</li>
<li name="tick" ph="tick6">Option 6</li>
</ul>
</div>
<div id="log"></div>
JS
//Get the ticker elements
var tickText = document.getElementById('newsTicker').getElementsByTagName('li');
var tickNum = tickText.length;
//New Array to clear empty data
var tickArry = [];
//Loop through list items and add non-void data to new loop
for(var a = 0; a < tickNum; a++) {
if ($(tickText[a]).html() != '') {
tickArry.push($(tickText[a]));
}
}
//Loop int
var i = 0;
var log = document.getElementById('log');
//Self-invoking function for ticker animation
function animTick() {
console.log($(tickArry[i]));
log.innerHTML += $(tickArry[i]).html();
//Make current tick item fall down
$(tickArry[i]).animate({'padding-top' : '+=50px'}, 500,
function() {
//Once tick item is off screen, reset values
$(this).css({'margin-left' : '9999px', 'padding-top' : '0'});
});
//Increment item
i++;
//If the tick has reach its length then reset
if (i === tickNum) {
i = 0;
//Else call the animation for the next tick
}
}
//Immediately animate in first list item
$(tickArry[i]).animate({'margin-left' : '0px'}, 2000);
//Add a delay
setInterval(animTick, 3000);
What if you include $(tickArry[i]).animate({'margin-left' : '0px'}, 2000); inside your animTick function?
Demo: Fiddle
Use setTimeout() if you are recursively calling the same function.
Your setInterval() alternative would be:
function animTick() {
// Function definition
}
setInterval(animTick, 3000);