Jquery associate two arrays - javascript

I would realy appreciate any help with this. Is there any way to simplify this code? I would like to pair elements of both arrays with the same index to perform specific functions.
var insects = ['#redhairy', '#bollworm', '#stalk', '#stem', '#chuija', '#diamond', '#pyrilla'];
var plants = ['.groundnut', '.cotton', '.maize', '.rice', '.wheat', '.mustard', '.sugarcane'];
$(insects[0]).hover(function(){
$(plants[0]).toggleClass('active');
});
$(insects[1]).hover(function(){
$(plants[1]).toggleClass('active');
});
$(insects[2]).hover(function(){
$(plants[2]).toggleClass('active');
});
$(insects[3]).hover(function(){
$(plants[3]).toggleClass('active');
});
$(insects[4]).hover(function(){
$(plants[4]).toggleClass('active');
});
$(insects[5]).hover(function(){
$(plants[5]).toggleClass('active');
});
$(insects[6]).hover(function(){
$(plants[6]).toggleClass('active');
});

If you have access to the HTML you could add a data attribute to the elements which receive the hover event which is the selector for the element that is to have the class toggled. This way you can group them with a common class and only use one selector, like this:
$('.item').hover(function() {
$($(this).data('target')).toggleClass('active');
});
.active {
color: #C00;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="redhairy" class="item" data-target=".groundnut">Red hariy</div>
<div id="bollworm" class="item" data-target=".cotton">Bollworm</div>
<div class="groundnut">Groundnut</div>
<div class="cotton">Cotton</div>
Alternatively, if you can't amend the HTML you could loop through the array and put a event handler on each element individually, using the index of the loop to get each item from the array:
var insects = ['#redhairy', '#bollworm', '#stalk', '#stem', '#chuija', '#diamond', '#pyrilla'];
var plants = ['.groundnut', '.cotton', '.maize', '.rice', '.wheat', '.mustard', '.sugarcane'];
insects.forEach(function(insect, i) {
$(insect).hover(function() {
$(plants[i]).toggleClass('active');
});
});
.active {
color: #C00;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="redhairy" class="item">Red hariy</div>
<div id="bollworm" class="item">Bollworm</div>
<div class="groundnut">Groundnut</div>
<div class="cotton">Cotton</div>
Note that the first method, which amends the HTML, is by far the better option here. Also note that forEach() relies on browser support of ES2015. If you need to support older browsers (such as IE) you'll need to use a polyFill, or a for() loop instead.

You could build a matrix (2D Array) with per line the insect and its plant. this build is easy with map().
var insects = ['#redhairy', '#bollworm', '#stalk', '#stem', '#chuija', '#diamond', '#pyrilla'];
var plants = ['.groundnut', '.cotton', '.maize', '.rice', '.wheat', '.mustard', '.sugarcane'];
var pairs = insects.map((x,i) => [x, plants[i]]);
console.log(pairs);

Related

How do I add classes to an unspecified amount of elements

I feel like this should be simple enough but I tend to overthink things. I simply want to add new classes to only the container-1 elements. The classes need to be numbered to differentiate them. Bonus for multiple methods & explaining in detail as I'd like to learn how to do this properly.
Example:
<div class="scroller">
<div class="container-1 newClass1"></div>
<div class="container-1 newClass2"></div>
<div class="container-2"></div>
<div class="container-1 newClass3"></div>
<div class="container-2"></div>
</div>
As the title says, the amount can be random. So it needs to read & apply to all container-1 within the scroller.
Here is some js, which get all elements by class name "container-1". After that in for loop, it will add class "newClass" with counter mark to each of the element with this class.
var elements = document.getElementsByClassName("container-1");
for(var i = 0; i < elements.length; i++){
elements[i].classList.add("newClass" + (i+1));
}
Well, one method I can think of is:
let selectedContainers = Array.from(document.querySelectorAll('.container-1'));
selectedContainers.map((container, i)=>{
container.classList.add(`newClass${++i}`)
})
What's going on here is that you're selecting all the divs with the container-1 class and creating an array from the NodeList. Then you're mapping through the array to access each element. Using template strings, you add a class name with a dynamic variable being the index of the container. You could use other variables and just increment them after, but I think the index is the easiest solution. Also, the reason I used ++i is to avoid getting a class with a zero index e.g newClass0
You can create an array of all the elements having class name 'container-1 using document.getElementsByClassName and the spread operator(...). Spread operator is used here because getElementsByClassName returns a HTMLCollection. So to iterate over it easily using a forEach we need to convert it to an array. Once converted, we could iterate over it and add newClass class to every element. To get the number to be added to the end of each newClass we use the 2nd argument to forEach which is index of the current element.
const containerOneDivs = [...document.getElementsByClassName('container-1')];
containerOneDivs.forEach((div, i) => div.className += ` newClass${i+1}`);
You can use querySelector (just to teach people who still use jQuery) to query for DOM elements.
You can then use Array.forEach to iterate over the list, and use $node.classList.add to append a class name.
Just for the purpose of the example:
window.onload = function onload () {
document.getElementById('btn-add').addEventListener('click', add, true);
document.getElementById('btn-remove').addEventListener('click', remove, true);
}
function add(e) {
updateFocus(e.target);
const list = document.querySelectorAll('.container-1');
list.forEach((item, i) => item.classList.add(`newClass-${i}`));
}
function remove(e) {
updateFocus(e.target);
const list = document.querySelectorAll('.container-1');
list.forEach((item, i) => item.classList.remove(`newClass-${i}`));
}
function updateFocus(el){
document.querySelectorAll('.active').forEach((i) => i.classList.remove('active'));
el.classList.add('active');
}
.scroller {
height: 100%;
width: 100%;
}
div[class*="container"] {
display: inline-block;
border: 1px solid blue;
width: 20px;
height: 20px;
margin: 2px;
}
div[class*="newClass-"] {
border: 1px solid yellow;
}
.active {
border: 3px solid red;
font-weight: bold;
}
<div class="scroller">
<div class="container-1"></div>
<div class="container-1"></div>
<div class="container-2"></div>
<div class="container-1"></div>
<div class="container-2"></div>
</div>
<button id="btn-add">add newClass-* to container-1</button>
<button id="btn-remove">remove newClass-* to container-1</button>
Otherwise it is just one line of code
document.querySelectorAll('.container-1');
.forEach((item, i) => item.classList.add(`newClass-${i}`));

How to remove one css class from div container with multiple elements and classes?

I want to get all elements which belong to two specific different classes and remove and add these classes seperately from these elements. I tried:
.concealed {
display: none;
}
.slide {
background: #333;
color: #fff;
}
// <div class="slide concealed">myText</div><br>
<div class="slide"><div class="concealed">myText</div></div><br>
<div class="slide"><div class="concealed">myText_2</div></div><br>
<div class="slide"><div class="concealed">myText_3</div></div><br>
// var slides = document.getElementsByClassName('slide');
// var slides = document.querySelectorAll('.slide, .concealed');
var slides = document.getElementsByClassName('slide concealed');
slides[0].classList.remove("concealed");
As you can see I tried several ways to achieve this but I can only remove and add "concealed" when I do var slides = document.getElementsByClassName('concealed'); . When doing getElementsByClassName with multiple classnames it seems to miss out concealed and only get slide. E.g. doing slides[0].classList.remove("concealed"); after document.getElementsByClassName('slide concealed'); has no effect.
I am sure I am missing something, this can't that hard to implement. Any ideas? Thanks.
The issue is that getElementsByClassName is a live HTMLCollection. When an element no longer matches (because you've removed the class), it's removed from the collection:
const list = document.getElementsByClassName("example");
console.log(list.length); // 2
console.log(list[0].innerHTML); // "A"
list[0].classList.remove("example");
console.log(list.length); // 1
console.log(list[0].innerHTML); // "B"
<div class="example">A</div>
<div class="example">B</div>
This means that if you're doing a loop and operate on the first entry, then increment your index, you'll miss what used to be the second entry because it's the first entry now.
A couple of ways to fix that:
Loop backward, or
Convert the HTMLCollection into an array before starting, or
Use querySelectorAll to get a snapshot NodeList instead, so that the lists contents don't change while you're updating.
Here's an example removing the classes red and bold from a series of elements using querySelectorAll so the NodeList is static:
setTimeout(() => {
const list = document.querySelectorAll(".red, .bold");
for (let n = 0; n < list.length; ++n) {
list[n].classList.remove("red");
list[n].classList.remove("bold");
}
}, 800);
.red {
color: red;
}
.bold {
font-weight: bold;
}
<div class="red">red 1</div>
<div class="bold">bold 1</div>
<div class="red bold">red 2 and bold 2</div>
<div class="bold">bold 3</div>
<div class="bold">bold 4</div>
See also my answer here: NodeList is now officially iterable, meaning you should be able to use a for-of loop on it. That answer shows how to polyfill that on slightly-older environments that haven't implemented it yet. It also shows how to add iterability to HTMLCollection (but note that HTMLCollection is not specified to be iterable).

console.log($('.divs').click(<function>)) shows an array of divs ... does the click method return the object it acts on?

console.log($('.divs').click(<function>))
This shows an array of divs.
Does the click method return the object it acts on?
It is just something basic - maybe someone can say more.
That $() returns the array of elements with that selector makes natural sense. But $(<selector>).click(<function definition>) - just defines what should happen on each element of $(<selector>) when it is clicked - why does it also "return" the array of elements?
Here is also a fiddle for the above http://jsfiddle.net/jy7kpL6f/
or here - HTML/CSS/jQuery
var addclass = 'color';
var $cols = $('.divs').click(function(e) {
$cols.removeClass(addclass);
$(this).addClass(addclass);
});
var $cols2 = $('.divs');
console.log($('.divs').click(function(e) {
$cols.removeClass(addclass);
$(this).addClass(addclass);
}));
.color {
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="divs">
1st Div
</div>
<div class="divs">
2nd Div
</div>
<div class="divs">
3rd Div
</div>
<div class="divs">
4th Div
</div>
click() returns all selected elements like many other jQuery functions.
This can be handy to chain functions like this:
$(".divs")
.click(callback1)
.hover(callback2)
...etc
Yes, it does. It returns the elements due to something called chaining. It enables such calls as:
$('div').addClass('on').removeClass('off');

How to create a search that filters by class name

I currently have a website that has multiple items. They are all individual div items. They all have one class name in common with several other class names as tags to help separate them (some tags are common among multiple div items)
I already have buttons set up that use data-filter=".exampleclass" and data-filter=".exampleclass2" etc. which work perfectly for sorting based on the class names. I am now trying to make a search bar where a user could type in the class name so I don't have to make buttons for them all.
document.getElementById("boxsearch").oninput = function() {
var matcher = new RegExp(document.getElementById("boxsearch").value, "gi");
for (var i = 0; i < document.getElementsByClassName("portfolio-item").length; i++) {
if (matcher.test(document.getElementsByClassName("category")[i])) {
document.getElementsByClassName("portfolio-item")[i].style.display = "inline-block";
} else {
document.getElementsByClassName("portfolio-item")[i].style.display = "none";
}
}
}
http://jsfiddle.net/kc2ot8ua/
I dont have the jquery file included so the buttons dont work (they work on my end) I just dont know how to use the search bar to search the class names.
This is the closest I could find to what I am trying to achieve: http://jsfiddle.net/mttgj1tt/5/
Filtering elements based on regular expression matches with one of their class names is an inefficient way to filter elements. Typically you'd build an index and use that with a more optimised search algorithm.
You might use one class to select the target set of elements, then loop over them and get their classList, then loop over those looking for matches, there's an example below. But this will also test other class names that have nothing to do with filtering or sorting (e.g. in the example below, "box" is used for display only, but elements are filtered by it anyway).
A better idea might be to add the filter and sorting values as a data- attribute, then they can be isolated from other side effects. I'd also suggest building an index of subject elements so you can find the ones you want first, then hide them.
Multiple getElementByClassName calls are expensive and unnecessary (particularly in a for loop). The example does one call per keyup.
function filterOnClass(baseClass, s) {
let re = new RegExp(s.trim(), 'i');
document.querySelectorAll('.' + baseClass).forEach(node => {
let cNames = Array.from(node.classList);
// Show all if search string is blank
if (s.trim() == '') {
node.classList.remove('hide');
// Otherwise, filter
} else if (cNames.some(cName => re.test(cName))) {
node.classList.add('hide');
} else {
node.classList.remove('hide');
}
});
}
.box {
height: 50px;
width: 100px;
border: 1px solid blue;
}
.hide {
display: none;
}
<input id="searchInput" onkeyup="filterOnClass('box', this.value)"><br>
<div class="box foo">foo</div>
<div class="box foo bar">foo bar</div>
<div class="box fum bar">fum bar</div>
<div class="box fum">fum</div>

How to select a specific <span> with the same class names?

I am attempting to extract some data from this block of HTML.
<div class="group-capitalization-content field-group-html-element">
<h2><span>Capitalization</span></h2>
<div class="item">
<div class="label-inline">Issued & Outstanding: </div>
<span class="number">242906121</span>
</div >
<div class="item">
<div class="label-inline">Reserved for Issuance: </div>
<span class="number">51423534</span >
</div>
</div>
I'm using an npm module called cheerio to scrape data from HTML. Thus I have the following code to try and get the "numbers".
var data = $('.group-capitalization-content .item .number').text();
Running this code results in: 24290612151423534, which is both results appended together.
How do I select the individual numbers here / separate them?
If the above example is all you need, use .eq().
First items's text() is
$('.group-capitalization-content .item .number').eq(0).text();
...and second is
$('.group-capitalization-content .item .number').eq(1).text();
If you have a more complex case and you need to store the data in an array, for later, I'd use $.map() (#Sushanth's answer) - probably a bit more specific, to rule out the possibility of other .numbers in the page:
let data = $.map(
$('.group-capitalization-content .item .number'),
function(e){ return $(e).text() }
);
You could you map method and target the .number class, which will spit out the contents into an array.
let data = $.map($('.number'), function(elem) {
return $(elem).text();
});
console.log(data);
If you don't know ahead of time how many there will be you can loop through them with an .each
$('.group-capitalization-content .item .number').each(function() {
$(this).text(); // Save this to a var or do something with it
});
How about each function to go through each of your results, like:
$('.group-capitalization-content .item .number').each(function(index, element) {
//your individual item code goes here
console.log( index + ": " + $( this ).text() );
});
i usually get all the dom elements and then loop over them to do my necessary functions. here is a working fiddle. https://jsfiddle.net/bbmtk7tm/
var data = $('.group-capitalization-content .item .number');
for(var i=0; i<data.length;i++)
{
console.log(data[i].innerHTML);
}

Categories

Resources