How to get a index of class onhover? - javascript

I have the following div structure:
<div class="0">
<div class="test"></div>
</div>
<div class="1">
<div class="test"></div>
</div>
<div class="2">
<div class="test"></div>
</div>
<div class="3">
<div class="test"></div>
</div>
For example, if I hover on the 1st class: document.getElementbyClassName('test')[0], I should get index value is 0.
Edit: I'm looking for a pure JS solution

You can use the following code:
$('.test').mouseenter(function() {
console.log("index: " + $(this).index('.test'));
})
$('.test').mouseenter(function() {
console.log("index: " + $(this).index('.test'));
})
.test {
height: 100px;
width: 100px;
border: 1px solid blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="test"></div>
<div class="test"></div>
<div class="test"></div>
<div class="test"></div>

To do this in pure JS you can use querySelectorAll() to retrieve the target elements and bind a mouseenter event handler to them. Then you can find the index of the element which triggered the event by comparing it to the collection of children in the parent. Something like this:
let elements = document.querySelectorAll('.test');
elements.forEach(el => el.addEventListener('mouseenter', e => {
let index = Array.from(elements).indexOf(e.target);
console.log(index);
}));
<div class="1">
<div class="test">Test 1</div>
</div>
<div class="2">
<div class="test">Test 2</div>
</div>
<div class="3">
<div class="test">Test 3</div>
</div>
<div class="4">
<div class="test">Test 4</div>
</div>

This code Use pure java script :
var divItems = document.querySelectorAll(".test");
var mytab = [];
var index = 0;
for (let i = 0; i < divItems.length; i++) {
mytab.push(divItems[i].innerHTML);
}
for (var i = 0; i < divItems.length; i++)
{
divItems[i].onmouseover = function ()
{
index = mytab.indexOf(this.innerHTML);
console.log(this.innerHTML + " Index = " + index);
};
}
<div class="test">Hover me 1</div>
<div class="test">Hover me 2</div>
<div class="test">Hover me 3</div>
<div class="test">Hover me 4</div>

Related

Javascript forEach loop with current index after new element was deleted

I am trying to get the updated index of the forEach loop after an element has been removed from the DOM.
Here is my current script ...
function delete(){
var elm = document.querySelectorAll('.divs');
elm.forEach(function(item, index){
item.addEventListener('click', function(e){
document.querySelectorAll('.divs')[index].remove();
});
}
after the element was removed the calculations for the index are incorrect.
how can I get the index of the clicked item after one or more items has been removed?
I've a very simple solution, but I don't know if you can accept it!
Node list in DOM is always live, if you refer to it as a variable, this variable is active. Check here:
https://developer.mozilla.org/en-US/docs/Web/API/NodeList
I propose you just to hide it!
listDivs1();
deleteDiv1();
function listDivs1() {
let ht = '';
let els = document.querySelectorAll('#method1 .divs');
els.forEach(function(e, index) {
ht += 'index: ' + index + ' - ' + e.innerHTML + '<br>';
});
document.querySelector('.elements1').innerHTML = ht;
}
function deleteDiv1() {
let els = document.querySelectorAll('#method1 .divs');
els.forEach(function(item, index) {
item.addEventListener('click', function(e) {
document.querySelectorAll('.divs')[index].remove();
listDivs1();
});
});
}
listDivs2();
deleteDiv2();
function listDivs2() {
let ht = '';
let els = document.querySelectorAll('#method2 .divs');
els.forEach(function(e, index) {
ht += 'index: ' + index + ' - ' + e.innerHTML + '<br>';
});
document.querySelector('.elements2').innerHTML = ht;
}
function deleteDiv2() {
let els = document.querySelectorAll('#method2 .divs');
els.forEach(function(item, index) {
item.addEventListener('click', function(e) {
e.target.remove();
listDivs2();
});
});
}
listDivs3();
deleteDiv3();
function listDivs3() {
let ht = '';
let els = document.querySelectorAll('#method3 .divs');
els.forEach(function(e, index) {
if (e.style.display !== 'none') {
ht += 'index: ' + index + ' - ' + e.innerHTML + '<br>';
}
});
document.querySelector('.elements3').innerHTML = ht;
}
window.addEventListener('load', listDivs3);
function deleteDiv3() {
let els = document.querySelectorAll('#method3 .divs');
els.forEach(function(item, index) {
item.addEventListener('click', function(e) {
e.target.style.display = 'none';
listDivs3();
});
});
}
.container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: 1fr;
grid-column-gap: 0px;
grid-row-gap: 0px;
padding: 1em;
}
<h1>your delete</h1>
<div class="container">
<div id="method1">
<div class="divs">div 0</div>
<div class="divs">div 1</div>
<div class="divs">div 2</div>
<div class="divs">div 3</div>
<div class="divs">div 4</div>
<div class="divs">div 5</div>
<div class="divs">div 6</div>
<div class="divs">div 7</div>
<div class="divs">div 8</div>
<div class="divs">div 9</div>
</div>
<div class="elements1"></div>
</div>
<hr>
<h1>e.target</h1>
<div class="container">
<div id="method2">
<div class="divs">div 0</div>
<div class="divs">div 1</div>
<div class="divs">div 2</div>
<div class="divs">div 3</div>
<div class="divs">div 4</div>
<div class="divs">div 5</div>
<div class="divs">div 6</div>
<div class="divs">div 7</div>
<div class="divs">div 8</div>
<div class="divs">div 9</div>
</div>
<div class="elements2"></div>
</div>
<hr>
<h1>display none</h1>
<div class="container">
<div id="method3">
<div class="divs">div 0</div>
<div class="divs">div 1</div>
<div class="divs">div 2</div>
<div class="divs">div 3</div>
<div class="divs">div 4</div>
<div class="divs">div 5</div>
<div class="divs">div 6</div>
<div class="divs">div 7</div>
<div class="divs">div 8</div>
<div class="divs">div 9</div>
</div>
<div class="elements3"></div>
</div>
In the snippet you 2 columns, the one with the divs to click, and second one with index and div content to check after each delete the result.
So with your function, index and div disconnect. With e.target same. With display none, it's working because nothing has been really removed, only "visually" removed. If you have other functions iterating through all those divs you'll have to exclude the display none like in listDivs3 function.
If this display none doesn't suit you, The only way would be:
store all div in temporary variable
remove the one you need
remove the node list
put the divs from the new list
re add your even listener

Get next element with class (that's not a child or sibling)

With the press of a button, I want to toggle the class .active on the next div.bottom. These are basically accordions, but with a different structure.
Using nextElementSibling I guess won't work here to select the target element. How would one select such an element, that's neither a child nor a sibling (in plain JS)?
<div class="wrapper">
<div class="top">
<div class="inner">
<div><button></button></div>
</div>
</div>
<div class="bottom"></div>
</div>
<div class="wrapper">
<div class="top">
<div class="inner">
<div><button></button></div>
</div>
</div>
<div class="bottom"></div>
</div>
I'd do it by using closest to go up to the container .wrapper element, then querySelector to find the bottom element:
function onClick(event) {
const wrapper = event.target.closest(".wrapper");
const bottom = wrapper && wrapper.querySelector(".bottom");
if (bottom) {
bottom.classList.toggle("active");
}
}
Live Example:
// I've added event delegation here
document.body.addEventListener("click", function onClick(event) {
const button = event.target.closest(".inner button");
const wrapper = button && button.closest(".wrapper");
const bottom = wrapper && wrapper.querySelector(".bottom");
if (bottom) {
bottom.classList.toggle("active");
}
});
.active {
color: blue;
border: 1px solid black;
}
<div class="wrapper">
<div class="top">
<div class="inner">
<div><button>Button A</button></div>
</div>
</div>
<div class="bottom">Bottom A</div>
</div>
<div class="wrapper">
<div class="top">
<div class="inner">
<div><button>Button B</button></div>
</div>
</div>
<div class="bottom">Bottom B</div>
</div>
Or the same thing using optional chaining (relatively new):
function onClick(event) {
const wrapper = event.target.closest(".wrapper");
const bottom = wrapper?.querySelector(".bottom");
bottom?.classList.toggle("active");
}
Live Example:
// I've added event delegation here
document.body.addEventListener("click", function onClick(event) {
const button = event.target.closest(".inner button");
const wrapper = button?.closest(".wrapper");
const bottom = wrapper?.querySelector(".bottom");
bottom?.classList.toggle("active");
});
.active {
color: blue;
border: 1px solid black;
}
<div class="wrapper">
<div class="top">
<div class="inner">
<div><button>Button A</button></div>
</div>
</div>
<div class="bottom">Bottom A</div>
</div>
<div class="wrapper">
<div class="top">
<div class="inner">
<div><button>Button B</button></div>
</div>
</div>
<div class="bottom">Bottom B</div>
</div>
By using closest() you can traverse the DOM upwards. With this it's easy to just get the relevant .bottom and toggle the active class on this element.
document.querySelectorAll('button').forEach(button => {
button.addEventListener('click', (e) => {
e.currentTarget.closest('.wrapper').querySelector('.bottom').classList.toggle('active');
});
});
.bottom {
display: none
}
.bottom.active {
display: block
}
<div class="wrapper">
<div class="top">
<div class="inner">
<button type="button">Toggle</button>
</div>
</div>
<div class="bottom">Hidden content</div>
</div>
<div class="wrapper">
<div class="top">
<div class="inner">
<button type="button">Toggle 2</button>
</div>
</div>
<div class="bottom">Hidden content 2</div>
</div>

Adding a Div around the contents of 2 matched elements

I am trying to add a div with class name 'wrapped' around 2 divs with innerHTML 'one' and 'two'
<div class='blk'>one</div>
<div class='blk'>two</div>
Here I am trying to use the first and second 'clearfix' class element and use it as a selector to wrap the contents between them with a div. What I understand from the below code is wrapAll will wrap only the matched elements. I am trying to figure out what functionality in jquery will help me to wrap one and two with a parent div.
var arr = $('.clearfix');
$(arr[0], arr[1]).wrapAll('<div class="wrapped"/>');
.wrapped {
background-color: 'red';
}
.hidden {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<div class='clearfix'></div>
<div class='blk'>one</div>
<div class='blk'>two</div>
<div class='clearfix'></div>
<div class='blk'>3</div>
<div class='blk'>4</div>
<div class='clearfix'></div>
</div>
My expected output is :
<div>
<div class='clearfix'></div>
<div class='wrapped'>
<div class='blk'>one</div>
<div class='blk'>two</div>
</div>
<div class='clearfix'></div>
<div class='blk'>3</div>
<div class='blk'>4</div>
<div class='clearfix'></div>
</div>
If I understand the question correctly, you're wanting to wrap a div (with class wrapped) around the two elements (with class blk) that contain the text content; "one" and "two".
One way to achieve this would be via the :eq selector - this allows you to isolate specific elements for the .blk class selector (ie the first and second), and than apply wrapping to those only:
/* Select the first and second elements that match the .blk selector
and apply wrapped div to those only */
$('.blk:eq(0), .blk:eq(1)').wrapAll('<div class="wrapped"/>');
.wrapped{
background-color: red; /* Fixed syntax error here too :) */
}
.hidden{
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<div class='clearfix'></div>
<div class='blk'>one</div>
<div class='blk'>two</div>
<div class='clearfix'></div>
<div class='blk'>3</div>
<div class='blk'>4</div>
<div class='clearfix'></div>
</div>
You can try with .filter()
var arr = $('.blk');
arr.filter((i, el) => i < 2).wrapAll(`<div class="wrapped"></div>`);
.wrapped{
background-color: red;
}
.hidden{
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<div class='clearfix'></div>
<div class='blk'>one</div>
<div class='blk'>two</div>
<div class='clearfix'></div>
<div class='blk'>3</div>
<div class='blk'>4</div>
</div>
var clearfixParent = $('.clearfix').parent();
var wrappedEle = 0;
$(clearfixParent).find( 'div' ).each(function(){
if( $(this).hasClass( 'clearfix' ) ) {
wrappedEle += 1;
$(this).after('<div class="wrapped"/>');
} else {
$(this).appendTo( '.wrapped:eq(' + ( wrappedEle - 1 ) + ')' );
}
});
.wrapped {
background-color: 'red';
}
.hidden {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<div class='clearfix'></div>
<div class='blk'>one</div>
<div class='blk'>two</div>
<div class='clearfix'></div>
<div class='blk'>3</div>
<div class='blk'>4</div>
<div class='clearfix'></div>
</div>
You don't need jQuery for this, you can use the DOM API.
const appendSelectedSiblings = selector => target => {
while (target.nextElementSibling && target.nextElementSibling.matches(selector))
target.appendChild(target.nextElementSibling)
}
document.querySelectorAll('.clearfix').forEach(appendSelectedSiblings('.blk'))
.clearfix > .blk { background: green };
<div id="root">
<div class='clearfix'></div>
<div class='blk'>one</div>
<div class='blk'>two</div>
<div class='clearfix'></div>
<div class='blk'>3</div>
<div class='blk'>4</div>
<div class='clearfix'></div>
</div>
From what I understood with the markup you included, you want to enclose/group all the divs with class BLKs that are beside each other.
I made a snippet that will be able to do this dynamically, without specifying the index of your wrap all.
Feel free to update if you could make the code more efficient.
var divs = $(".scan").find("div");
var toEnclose = [];
var continueEnclose;
var latestArray = [];
divs.each(function(i) {
if ($(this).hasClass("clearfix")) {
if (latestArray.length != 0) {
toEnclose.push(latestArray);
latestArray = [];
}
}
if ($(this).hasClass("blk")) {
latestArray.push(i);
}
});
if (latestArray.length != 0) {
toEnclose.push(latestArray);
latestArray = [];
}
var enclose;
var mix = [];
$.each(toEnclose, function(i, k) {
$.each($(this), function(i2, k2) {
if (i != 0) {
k2 += i;
}
mix.push(".scan div:eq(" + k2 + ")");
});
enclose = mix.join(",");
// console.log(enclose);
$(enclose).wrapAll($("<div class='wrapped'></div>"));
mix = [];
});
.wrapped {
background-color: red;
margin-bottom: 5px;
}
.hidden {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="scan">
<div class='clearfix'></div>
<div class='blk'>one</div>
<div class='blk'>two</div>
<div class='clearfix'></div>
<div class='blk'>3</div>
<div class='blk'>4</div>
<div class='clearfix'></div>
<div class='blk'>5</div>
<div class='blk'>6</div>
<div class='blk'>7</div>
</div>

show certain elements in an array

I have a 6 divs (although the code should work for any number of divs). I want to show 4 divs at a time when the button #more-projects is clicked. Ideally, the the first 4 divs would be shown when the #more-projects is clicked for the first time, when it's clicked again all divs are hidden and then the next divs are shown in this case it would be 5 and 6 would be along with 1 and 2. Whenever the #more-projects is clicked the next four divs would be shown. Below is my approach but I don't know how to progress
$('#more-projects').on('click', function() {
var projects = [];
var shown = [];
var start = [];
$('.thumbnail-cnt').each(function(i) {
projects.push($(this).data('num'));
})
var shown = projects.slice(0,4);
$('[data-num="' + shown.join('"], [data-id="') + '"]').addClass('visible');
});
.thumbnail-cnt {
display: none;
}
.visible {
display: block;
}
<script
src="https://code.jquery.com/jquery-1.12.4.min.js"
integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="
crossorigin="anonymous"></script>
<div class="thumbnail-cnt" data-num="1">
</div>
<div class="thumbnail-cnt" data-num="2">
</div>
<div class="thumbnail-cnt" data-num="3">
</div>
<div class="thumbnail-cnt" data-num="4">
</div>
<div class="thumbnail-cnt" data-num="5">
</div>
<div class="thumbnail-cnt" data-num="6">
</div>
<button id="more-projects">
</button>
From here I was going slice the projects to be shown, add class .visible and make a var of the index in the array that should be the starting point of the next 4 projects. But I don't know how to implement this of to cycle back to the start of the array. Any help would be appreciated.
Please check this code
HTML
<div id="container">
<div class="thumbnail-cnt" data-num="1">1
</div>
<div class="thumbnail-cnt" data-num="2">2
</div>
<div class="thumbnail-cnt" data-num="3">3
</div>
<div class="thumbnail-cnt" data-num="4">4
</div>
<div class="thumbnail-cnt" data-num="5">5
</div>
<div class="thumbnail-cnt" data-num="6">6
</div>
</div>
<button id="more-projects" > Next
</button>
JS
$(document).ready(function(){
var divQueue = [];
$("#container div").each(function(){
divQueue.push($(this));
});
function showDivs(){
$("#container").html('');
$(".thumbnail-cnt").css("display","none");
var i=0;
while(i<4){
var temp = divQueue[0];
$("#container").append(temp[0]);
divQueue.shift();
divQueue.push(temp);
i++;
}
}
showDivs();
$("#more-projects").click(function(){
showDivs();
});
});
CSS
.thumbnail-cnt {
height : 30px;
width : 25px;
}
#more-projects {
width : 100px;
height : 50px;
}
Please refer Fiddle
I would try to assign an id for each div, something like:
<div class="thumbnail-cnt" id="div1" data-num="1">
</div>
<div class="thumbnail-cnt" id="div2" data-num="2">
</div>
<div class="thumbnail-cnt" id="div3" data-num="3">
</div>
<div class="thumbnail-cnt" id="div4" data-num="4">
</div>
<div class="thumbnail-cnt" id="div5" data-num="5">
</div>
If you are using Jquery you can use the methods hide() and show()
If you want to show X divs:
for(var i = 1; i < X; i ++){
$('#div'+i).show();
}
for(var i = X; i < numDivs; i ++){
$('#div'+i).hide();
}
Using arrays have managed to rotate the divs. Check if this is what you are looking for:
var divs = [];
$('.thumbnail-cnt').each(function() {
divs['' + $(this).index() + ''] = $(this).data('num');
divs.push($(this).text());
});
divs.splice(0, 1);
$('#more-projects').on('click', function() {
$('.thumbnail-cnt').hide();
var count = 0;
$(divs).each(function(k, v) {
if (count == 4)
return false;
$('.thumbnail-cnt[data-num="' + v + '"]').show();
divs.push(divs.shift());
count++;
});
});
.thumbnail-cnt {
display: none;
}
.visible {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="thumbnail-cnt" data-num=1>Test 1</div>
<div class="thumbnail-cnt" data-num=2>Test 2</div>
<div class="thumbnail-cnt" data-num=3>Test 3</div>
<div class="thumbnail-cnt" data-num=4>Test 4</div>
<div class="thumbnail-cnt" data-num=5>Test 5</div>
<div class="thumbnail-cnt" data-num=6>Test 6</div>
<div class="thumbnail-cnt" data-num=7>Test 7</div>
<div class="thumbnail-cnt" data-num=8>Test 8</div>
<div class="thumbnail-cnt" data-num=9>Test 9</div>
<button id="more-projects">More</button>

Wrap multiple div elements on same class

I would like to use jQuery to wrap sets of class elements in a div but can't find the solution.
HTML:
<div class="view-content">
<div class="first">content</div>
<div class="first">content</div>
<div class="second">content</div>
<div class="third">content</div>
<div class="third">content</div>
</div>
Desired Result:
<div class="view-content">
<div class="column">
<div class="first">content</div>
<div class="first">content</div>
</div>
<div class="column">
<div class="second">content</div>
</div>
<div class="column">
<div class="third">content</div>
<div class="third">content</div>
</div>
</div>
Demo http://jsfiddle.net/kQz4Z/8/
API: http://api.jquery.com/wrapAll/
Added a break line so that you can see the difference here :) http://jsfiddle.net/kQz4Z/10/
code
$(function() {
$('.first').wrapAll('<div class="column" />')
$('.second').wrapAll('<div class="column" />')
$('.third').wrapAll('<div class="column" />')
alert($('.view-content').html());
});​
Use wrapAll() method
$(function(){
var classes = ['.first', '.second', '.third'];
for (i = 0; i < classes.length; i++) {
$(classes[i]).wrapAll('<div class="column">');
}​
});
Demo: http://jsfiddle.net/g9G85/
Or here is the very short dynamical solution:
​$(".view-content > div").each(function() {
$(".view-content > ." + this.className).wrapAll("<div class='column' />");
});​
DEMO: http://jsfiddle.net/CqzWy/
You can use .wrap() to wrap something in a div but if your content is not ordered it will become a mess, here's an example:
Input
<div class="view-content">
<div class="first">content</div>
<div class="second">content</div>
<div class="first">content</div>
</div>
Output
<div class="view-content">
<div class="column">
<div class="first">content</div>
<div class="column">
<div class="second">content</div>
</div>
<div class="first">content</div>
</div>
</div>
You could try whit this:
var arr = $(".view-content div").map(function() { return $(this).attr('class'); }).get();
var results = $.unique(arr);
var i;
for(i = 0; i < results.length; i++){
$('.out').append('<div class="columns"></div>');
$('.'+results[i]).clone().appendTo('.columns:last');
}
alert($('.out').html());
Here an example:
JSFIDDLE

Categories

Resources