How can I access classes within arrays and style them using javascript - javascript

So let's say I have 3 different classes: one, two, and three. Each class has 3 div's like this:
<div class="one"></div>
<div class="one"></div>
<div class="one"></div>
<div class="two"></div>
<div class="two"></div>
<div class="two"></div>
<div class="three"></div>
<div class="three"></div>
<div class="three"></div>
Then I give each class a variable:
var _1 = document.getElementsByClassName("one");
var _2 = document.getElementsByClassName("two");
var _3 = document.getElementsByClassName("three);
Then I put them all in an array call nums:
var nums = [_1,_2,_3];
If I wanted to then go through and change the text color of every single div in the classes: one, two, and three. How would I go about doing that without doing something like this:
function textColor() {
var i;
for (i = 0; i < _1.length; i++) {
_1[i].style.color = "red";
}
for (i = 0; i < _2.length; i++) {
_2[i].style.color = "red";
}
for (i = 0; i < _3.length; i++) {
_3[i].style.color = "red";
}
}
I would really like to only have one for loop that goes through and gets all the items in the array nums, and then goes through and gets every div from every item in nums and changes the text color.

Use concat when putting them in nums (and convert the NodeLists to arrays)
var nums = Array.from(_1).concat(Array.from(_2)).concat(Array.from(_3));
Or use the spread operator
var nums = [..._1,..._2,..._3];
Then you can do
function textColor() {
nums.forEach(node => node.style.color = 'red');
}

You can flatten your nums array like this:
var flatNums = [].concat.apply([],nums)
and then go through it:
for (i = 0; i < flatNums.length; i++) {
flatNums[i].style.color = "red";
}

I would just do something like this:
$(".one, .two, .three").prop("style","color: red;");
Or add a second class for all nine div:s.

If you will apply same style to all divs, you can simplify things even more:
divs=document.querySelectorAll('.one, .two, .three');
divs.forEach(function(el) {
el.style.color='red';
})
divs=document.querySelectorAll('.one, .two, .three');
divs.forEach(function(el) {
el.style.color='red';
})
<div class="one">1</div>
<div class="one">2</div>
<div class="one">3</div>
<div class="6">
skip
</div>
<div class="two">4</div>
<div class="two">5</div>
<div class="two">6</div>
<div class="three">7</div>
<div class="three">8</div>
<div class="three">9</div>

Related

Including the current node in the find scope

Consider the following snippet as an example:
<div class="bar foo">
</div>
<div class="bar">
<div class="foo"></div>
</div>
Given var $set=$('.bar'); I need to select both nodes with foo class. What is the proper way to achieve this. Considering addBack() requires a selector and here we need to use the $set jQuery object and $set.find('.foo') does not select the first node.
use this :
var $set = $(".bar").filters(function () {
var $this = $(this);
if($this.is(".foo") || $this.find(" > .foo").length !== 0){
return true;
} else{
return false;
}
});
Here's one way of going about it:
var set = $('.bar');
var foos = [];
for (var i = 0; i < set.length; i++) {
if ($(set[i]).hasClass('foo')) {
foos.push(set[i]);
}
}
if (set.find('.foo').length !== 0) {
foos.push(set.find('.foo')[0]);
}
console.log(foos);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="bar foo"></div>
<div class="bar">
<div class="foo"></div>
</div>
The for loop checks all elements picked up with jQuery's $('.bar'), and checks if they also have the foo class. If so, it appends them to the array. The if checks if any of the elements picked up in set have any children that have the foo class, and also adds them.
This creates an array that contains both of the DIVs with the foo class, while excluding the one with just bar.
Hope this helps :)
test this :
var $newSet = $set.filter(".foo").add($set.has(".foo"));
You could use the addBack() function
var $set=$('.bar');
console.log($set.find(".foo").addBack(".foo"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="bar foo">
</div>
<div class="bar">
<div class="foo"></div>
</div>

How to sort a list of nodes by a given array in an efficient way?

I have this HTML which is a list of elements:
<div class="container">
<div class="apple-0">first-apple</div>
<div class="apple-1">second-apple</div>
<div class="apple-2">third-apple</div>
<div class="apple-3">forth-apple</div>
<div class="apple-4">fifth-apple</div>
</div>
I've gotten an array, for example, which is [3,4,0,2,1] I need to sort the list in to this order.By this I mean that the third element <div class="apple-3">third-apple</div> should be the first. The second element should be the forth-apple.
How can I change it in an efficient way? This is the expected output:
<div class="container">
<div class="apple-3">forth-apple</div>
<div class="apple-4">fifth-apple</div>
<div class="apple-0">first-apple</div>
<div class="apple-2">third-apple</div>
<div class="apple-1">second-apple</div>
</div>
jQuery can be used.
You can do this by looping through the array and appending each div by it's matched index. Try this:
var $divs = $('.container > div').detach();
[3, 4, 0, 2, 1].forEach(function(value) {
$divs.eq(value).appendTo('.container');
});
Working example
Note that if you need to support older browsers (< IE9) then you would need to replace forEach() with a standard for loop.
You can try something like this:
$("#sort").on("click", function() {
var data = [3, 4, 0, 2, 1];
var result = "";
data.forEach(function(item) {
result += $(".container").find(".apple-" + item)[0].outerHTML;
});
$(".container").html(result);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
<div class="container">
<div class="apple-0">first-apple</div>
<div class="apple-1">second-apple</div>
<div class="apple-2">third-apple</div>
<div class="apple-3">forth-apple</div>
<div class="apple-4">fifth-apple</div>
</div>
<button id="sort">Sort</button>
Simply iterate the indexes array and keep pushing the child at nth-index
var output = [];
var indexes = [3,4,0,2,1];
indexes.forEach(function(value, index){
output.push($(".container div").eq(indexes[index])[0].outerHTML);
});
console.log(output);
$(".container").html(output.join(""));
Demo
you can try:
UPDATE:
var arr = [3,4,0,2,1];
var nodes = [];
arr.forEach(funtion(value){
var node = $('.container .apple-'+value)[0];
nodes.push(node);
});
$('.container').html(nodes);
demo
Other answers with eq are good, but if you want to sort again with a different array, or the array is unsorted initially, then they would fail. Also you asked for an efficient method, using native loops instead of jquery's each gives performance benefits. So my answer to this is
$(document).ready(function () {
var inputEls = $('#awesomeContainer').find('>').get(),
$output = $('#awesomeOutput'),
order = [3,4,0,2,1],
output = [],
myValue,
newIndex,
i,
length = inputEls.length;
for (i = 0; i < length; i += 1) {
myValue = Number((inputEls[i].className || "").replace("apple-", ""));
if (myValue >= 0) {
myValue = order.indexOf(myValue);
myValue > -1 && (output[myValue] = inputEls[i].outerHTML);
}
}
$output.append(output.join(''));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<b>Input: </b>
<div id="awesomeContainer" class="container">
<div class="apple-0">first-apple</div>
<div class="apple-1">second-apple</div>
<div class="apple-2">third-apple</div>
<div class="apple-3">forth-apple</div>
<div class="apple-4">fifth-apple</div>
</div>
<br/>
<b>Sorted: </b>
<div id="awesomeOutput" class="container">
</div>

Count nested divs in JavaScript

Hey I need to count the nested divs with a given class name. For example:
<div id = "divA">
<div class = "anotherName"></div>
<div class = "toBeCounted"></div>
<div class = "someName"></div>
<div class = "toBeCounted"></div>
<div class = "toBeCounted"></div>
<div class = ""></div>
</div>
<div id = "divB">
<div class = ""></div>
<div class = "toBeCounted"></div>
<div class = ""></div>
<div class = "toBeCounted"></div>
</div>
So if I want to count "toBeCounted" I would get 3 for divA and 2 for divB.
You can use .querySelectorAll() and check the length of the result:
var divAcount = document.querySelectorAll("#divA > .toBeCounted").length;
The > relation insists that the .toBeCounted elements are immediate children of divA. If that's not what you want, and any toBeCounted div within divA should count, you'd just leave out the >.
try this pure javascript code
var countinDivA = document.getElementById("divA").getElementsByClassName("toBeCounted").length;
var countinDivB = document.getElementById("divB").getElementsByClassName("toBeCounted").length;
With Jquery this can be easily achieved by using
var countA = $("#divA .toBeCounted").length;
var countB = $("#divB .toBeCounted").length;
If you don't know the id's of the parents ahead of time, this may prove useful:
var parents = [],
counted = document.getElementsByClassName("toBeCounted");
for (var i=0; i < counted.length; i++ ) {
var id = counted[i].parentNode.id;
if ( !parents[id] ) parents[id] = 1
else parents[id]++;
}
[ divA: 3, divB: 2 ]

I'm looping over an array and modifying the contents of the array, but I don't get the results I expect.

I'm looping over an array and modifying the contents of the array, but I don't get the results I expect. What am I missing or doing wrong?
I have two groups of divs (one with class attacker, and other enemy) with three elements each. I am trying to select one element from each side by making a border around it. Now i want to toggle classes from a attacker to enemy and the other way.
But when I use for loop it somehow ignores some elements and changes only one or two div classes. Here is my code:
HTML:
<div id="army1">
<div class="attacker">
<img src="img/Man/Archer.jpg" />
<div class="hp"></div>
</div>
<br><div class="attacker">
<img src="img/Man/Knight.jpg" />
<div class="hp"></div>
</div>
<br><div class="attacker">
<img src="img/Man/Soldier.jpg" />
<div class="hp"></div>
</div>
<br>
</div>
<div id="army2">
<div class="enemy">
<img src="img/Orcs/Crossbowman.jpg" />
<div class="hp"></div>
</div>
<br><div class="enemy">
<img src="img/Orcs/Mine.jpg" />
<div class="hp"></div>
</div>
<br><div class="enemy">
<img src="img/Orcs/Pikeman.jpg" />
<div class="hp"></div>
</div>
<br>
</div>
And my javascript code:
var attacker = document.getElementsByClassName('attacker');
var enemy = document.getElementsByClassName('enemy');
var button = document.getElementById("fight");
// var class1 = document.getElementsByClassName("first")[0].getAttribute("class");
// class1 = class1.split(" ");
//choose attacker
for (var i = 0; i < attacker.length; i++) {
attacker[i].onclick = function () {
//select only one attacker and set its id to attackerid
if (this.getAttribute('class') != 'attacker first') {
resetAttackerClasses();
this.setAttribute('class', 'attacker first');
} else {
resetAttackerClasses();
}
};
}
//choose enemy
for (var i = 0; i < enemy.length; i++) {
enemy[i].onclick = function () {
//select only one attacker and set its id to enemyid
if (this.getAttribute('class') != 'enemy second') {
resetEnemyClasses();
this.setAttribute('class', 'enemy second');
} else {
resetEnemyClasses();
}
};
}
//fight
button.onclick = function() {
//take off enemy health
document.getElementsByClassName('enemy second')[0].children[1].style.width = '50px';
resetAttackerClasses();
resetEnemyClasses();
for (var i = 0; i < attacker.length; i++) {
attacker[i].setAttribute('class', 'enemy');
enemy[i].setAttribute('class', 'attacker');
};
};
function resetAttackerClasses() {
for (var i = 0; i < attacker.length; i++) {
attacker[i].setAttribute('class', 'attacker');
};
}
function resetEnemyClasses() {
for (var i = 0; i < attacker.length; i++) {
enemy[i].setAttribute('class', 'enemy');
};
}
It's because you're removing the class that was used to fetch the element, which means the element will automatically be removed from the live NodeList (since it no longer matches the query).
When this happens, the NodeList is reindexed, so the next element becomes the current one, and you end up skipping over it with the next i++;
To fix it, iterate in reverse instead.
If you don't want to go in reverse, then decrement the index every time you remove an element from the list.

How to get the count of the DIVs with almost the same ID property?

I have many DIVs on my page with the same ID
eg:
<div id="myDiv1">
...
</div>
<div id="myDiv2">
...
</div>
<div id="myDiv3">
...
</div>
...
<div id="myDiv20">
...
</div>
...
As You see, the ID property looks almost the same - the only diffrence is that there is a number in each ID.
How to get the count of that DIVs? I thought I can do something like that:
var myDivs= document.getElementById('myDiv');
but returns null
You can do this using jQuery like this:
$('div[id^=myDiv]')
If you can't use jQuery, you'll need to call getElementsByTagName and loop through the values checking the ID property.
var divs = document.getElementsByTagName('div');
var counter = 0;
for(var i in divs) {
if(divs[i].id.indexOf('myDiv') === 0) {
counter++;
}
}
or just
document.querySelectorAll('[id^=myDiv]').length
you can use jquery
//this will give you all divs start with myDiv in the id
var divs = $("div[id^='myDiv']");
From this site:
function getElementsByRegExpId(p_regexp, p_element, p_tagName) {
p_element = p_element === undefined ? document : p_element;
p_tagName = p_tagName === undefined ? '*' : p_tagName;
var v_return = [];
var v_inc = 0;
for(var v_i = 0, v_il = p_element.getElementsByTagName(p_tagName).length; v_i < v_il; v_i++) {
if(p_element.getElementsByTagName(p_tagName).item(v_i).id && p_element.getElementsByTagName(p_tagName).item(v_i).id.match(p_regexp)) {
v_return[v_inc] = p_element.getElementsByTagName(p_tagName).item(v_i);
v_inc++;
}
}
return v_return;
}
Usage:
var v_array = getElementsByRegExpId(/^myDiv[0-9]{1,2}/);

Categories