How to find index of previous active class - javascript

I am trying to make a slider. Most of it is working till here, but I am not getting further as I want to find the index of the item which I removed the class as last from.(before the click)
So when I click on a dot, the clicked dot must be enabled and get the active class and the class on the previous active dot needs to be removed.
navDots.addEventListener('click', e => {
// make only dot's clickable
const targetDot = e.target.closest('.dots');
// disable NavDots for clicks
if(!targetDot)return;
//Find the index of the clicked btn
const dotIndex = Array.from(targetDot.parentNode.children).indexOf(targetDot);
console.log(dotIndex);
// Add the active class tot the dot
navDots.children[dotIndex].classList.add('active');
//HOW TO REMOVE PREVIOUS DOT ACTIVE style?
//show image with dotIndex
showImages(dotIndex);
});
Thank you for helping,
r,y.

The most efficient way is to store active element in a variable:
let activeElement = null;
navDots.addEventListener('click', e => {
// make only dot's clickable
const targetDot = e.target.closest('.dots');
// disable NavDots for clicks
if(!targetDot)return;
//Find the index of the clicked btn
const dotIndex = Array.from(targetDot.parentNode.children).indexOf(targetDot);
console.log(dotIndex);
// remove previous active class
activeElement && activeElement.classList.remove("active");
// save new active element
activeElement = navDots.children[dotIndex];
// Add the active class tot the dot
activeElement.classList.add('active');
//HOW TO REMOVE PREVIOUS DOT ACTIVE style?
//show image with dotIndex
showImages(dotIndex);
});

Related

onclick inside forEach, value parameter only refers to last element

I have a list of anchor in my html, I want to make their href editable.
Everything fine, but the validation step (last onclick) refers to the last anchor instead of the current one
var anchors = document.querySelectorAll('.home-content a');
var col = document.querySelectorAll('.home-content > article');
anchors.forEach((k)=> {
let linkpanel = document.getElementById('link-edit-panel'); //This element is a single div in my html
let linkpanelvalidate = document.getElementById('validate-link'); //the button inside the said div
let editinput = linkpanel.querySelector('input'); //the input inside this div
//For each anchors, I add a button that will let user show the "linkpanel" div to edit the href of this anchor
let editbut = document.createElement('div');
let linktxt = k.href;
editbut.classList.add('edit-but','toremove');
editbut.innerHTML = "<i class='fas fa-link'></i>";
//I put this new element to the current anchor
k.appendChild(editbut);
console.log(k); // this to show me the full list of anchors
/* PROBLEM START HERE */
//click on the "edit" button
editbut.onclick = ()=>{
console.log(k); //Here, it shows the good anchor!
}
//click on the "validate" button
linkpanelvalidate.onclick = ()=>{
console.log(k); //Here, it shows the very last anchor...
}
});
I tried to put the element inside a constant
const ttt = k;
It does not change a thing.
Thank you for your help
We are facing here a classical forEach bubbling misunderstand (and I was blind not to see it)
When the click on the validate button occures, the call is made from the "main" bubble (outside the loop function if you need to picture it) so naturaly, it returns the last occurrence of the loop when we print the value in the console for example.
Solution
There is many solutions, you can store these values in an array to use each of them later
var arr = [];
node.forEach((v)=>{
arr.push(v);
});
Or, you don't want to deal with an array and want to keep it simple, like me, and you create your button during the forEach loop event, like this
node.forEach((v)=>{
let btn = document.createElement('button');
document.body.appendChild(btn);
btn.onclick = ()=> {
console.log(v); //it is the current value, not the last one
//you can create another button here and put his onclick here, the value will still remains etc
}
});

Get non hidden element with previousElementSibling

I have a long list of items. One of them is active. From that active item I want to go to the previous one. I can do that with previousElementSibling.
The problem is that I want to skip the hidden elements. How can I do that?
const active = document.querySelector('.active');
const prev = active.previousElementSibling;
console.log(active);
console.log(prev);
<div></div>
<div hidden></div>
<div class="active"></div>
In the real world, the list is dynamic and longer so no crazy hacks will work.
You can do this by looping to repeatedly walk through previousElementSibling's, until you find one that's not hidden. For example:
const active = document.querySelector('.active');
// Get the previous sibling
let result = active.previousElementSibling;
// If it's hidden, continue back further, until a sibling isn't hidden
while (result && result.hidden == true) {
result = result.previousElementSibling;
}
if (result) {
// You got a non-hidden sibling!
console.log(result);
} else {
// There is no previous sibling that's not hidden
}
You can keep going to previous elements until you find one that is not hidden or until you reach the first element :
const active = document.querySelector('.active');
let prev = active.previousElementSibling;
while (prev !== null) {
if (!prev.hidden) break;
prev = prev.previousElementSibling;
}
console.log(active);
console.log(prev);

Dom Traversing the Dom with JavaScript but event not hitting the Html Element

I want to add delete functionality to a button on an Li element that is dynamically created by Javascript but I can't seem to be able to get the event listener to hit the target button.
I tried adding it right away by doing
var trashButton = document.getElementsByClassName("deleteListItemButton");
trashButton.addEventListener('click',removeLiItem);
but I got an unhandled exception error
var idForLiElement =1;
document.getElementById("addTaskId").addEventListener('click', function(){
var valueFromTextBox = document.getElementById("textBoxId").value;
if(valueFromTextBox) addItemToDo(valueFromTextBox);
});
function addItemToDo(valueFromTextBox){
var unorderedList = document.getElementById("toDoId")
var listElement = document.createElement("li");
listElement.className ="listItem";
listElement.innerHTML = valueFromTextBox;
listElement.id =Number(idForLiElement);
idForLiElement ++;
//puts the newest list element before the last element
unorderedList.insertBefore(listElement, unorderedList.childNodes[0]);
//creates the div that will contain both buttons in each list element
var buttonsContainer = document.createElement("div");
buttonsContainer.className ="listItemButtonContainer";
//creates the delete button and assigns it a class name
var deleteButton = document.createElement("Button")
deleteButton.className ="deleteListItemButton";
//creates the complete button and assigns it a class name
var completeButton = document.createElement("Button")
completeButton.className ="completeListItemButton";
//creates the delete image tag and assigns it a class name
var trashImageTag = document.createElement("i")
trashImageTag.className = "fa fa-trash fa-2x";
//creates the check mark button and assigns it a class name
var checkMarkImageTag = document.createElement("i")
checkMarkImageTag.className= "fa fa-check fa-2x";
//appends delete image tag to delete button
deleteButton.appendChild(trashImageTag);
//appends check mark image tag to complete button
completeButton.appendChild(checkMarkImageTag);
//appends delete button to button container
buttonsContainer.appendChild(deleteButton);
//appends complete button to button container
buttonsContainer.appendChild(completeButton)
//appends button container to list element
listElement.appendChild(buttonsContainer);
};
var trashButton = document.getElementsByClassName("deleteListItemButton");
for (i = 0; i < trashButton.length; i++) {
trashButton[i].addEventListener('click',removeLiItem)
};
function removeLiItem(e){
console.log(this)
};
I just want the event listener to hit console.log so I know the button is working
Attach the event to the element you've just created
deleteButton.addEventListener('click', function() { console.log('hit!') })
I want to add delete functionality to a button on an Li element that is dynamically created by javascript but I cant seem to be able to get the event listener to hit the target button.
The elements are dynamically created, so by the time the elements are created, the for loop where you add the event listeners has already executed.
This is what event propogation is for. Let the parent element (ul) listen to event clicks instead of having each child hold the responsibility. That way it doesnt matter how many children elements are added, momma (parent element) will always be listening for clicks.
You can do something like this:
// on your ul element
const itemList = document.querySelector(".item-list");
// listen for click on here
itemList.addEventListener('click', removeLiItem);
// you can access the actual element through the event's `target`
function removeLiItem (event) {
if (event.target.classList.contains('deleteListItemButton') {
// remove element
}
}

Javascript remove child on click based on class

I'm making a basic list using vanilla javascript. I am able to add items, and change their class when they are clicked. Now, I want the items that have been selected (so their class has been changed) to be removed when they are clicked. At the bottom of the code, I am trying to loop through the list, then if the element in the list has the selected class, an event listener will remove the element when clicked, but this isn't working for me. Any ideas on what I'm doing wrong? (live demo: http://codepen.io/nicolaswilmot/pen/oXLgyq)
Here is the code:
var list = document.getElementById("theList"); // Get the list
// Add new item to top of list
function addItem(e) {
var userTxt = document.getElementById("userInput"); // Get user text
var newItem = document.createElement("li"); // Create new list item
var itemTxt = document.createTextNode(userTxt.value); // Get the text for item
newItem.appendChild(itemTxt); // Add text to list item
list.insertBefore(newItem, list.firstChild); // Put new item at top of list
newItem.className = 'defaultItem'; // Set default class for li
document.getElementById("userInput").value = ''; // Clear the input box
e.preventDefault(); // Prevent page from reloading when page is submitted
// Changes list item class
function changeClass () {
newItem.className = 'selectedItem';
}
// Initialize array for list items
listArray = [];
// Loop through list, add items to array, update class and counter
// when items are clicked
for (var i=0; i<list.children.length; i++) {
listArray.push(newItem);
listArray[i].addEventListener("click",changeClass);
listArray[i].addEventListener("click",countStuff);
}
}
var docForm = document.getElementById("theForm"); // Get the form element
docForm.addEventListener('submit',addItem,false); // Call addItem function when form is submitted
docForm.addEventListener('submit',countStuff,false); //Call counter when form submitted
// Function for the list item counter
function countStuff() {
// Get div container for counter
var itemCount = document.getElementById("counter");
// Get all list items that have not been selected (default class)
var unselectedItems = document.querySelectorAll('li.defaultItem');
//If more than one item, display plural "items"
if (unselectedItems.length > 1) {
itemCount.innerHTML = 'You still need '+unselectedItems.length+' items!';
} else if (unselectedItems.length == 0) {
itemCount.innerHTML = 'You have all items!';
} else {
itemCount.innerHTML = 'You still need '+unselectedItems.length+' item!';
}
}
// Loop through the list
for (var i=0; i<list.children.length; i++) {
// Remove items that are in selected state
if (list.childNodes[i].className='selectedItem') {
list.childNodes[i].addEventListener('click',function () {
list.removeChild([i])},false);
}
}
The placement of your code where you are trying to remove the element once it has the selectedItem class does not make sense, because that code will only run once on page load when the page has no items in the list. Instead, in the same function where you add the selectedItem class, you can bind an event listener to that DOM element that removes it from the list on the next click. http://codepen.io/anon/pen/vOKEzz
function changeClass () {
newItem.className = 'selectedItem';
//Remove it on click!
newItem.addEventListener('click',function () {
list.removeChild(newItem)
}, false);
}

Jquery - Toggle Image Src if Parent Class is Clicked Hide/Show

I have a program that is configured to hide/show table rows when a +/- icon is clicked. The functionality is working, however, I need to figure out a way to reset all hide/show icons when the parent category is toggled closed.
$(function(){
//src vars
var hide_src = "http://www.synchronizeddesigns.com/filter_hide.gif",
reveal_src = "http://www.synchronizeddesigns.com/filter_reveal.gif",
s = '';
//hide all sublevel elements
$(".subsub, .subsubsub").hide();
$("a").click(function(e){
e.preventDefault();
var tID = e.target.id,
tClass = '.' + tID.replace('HS', '');
$(tClass).toggle();
if(!$(tClass).is(':visible')){
s = hide_src;
//for each subcategory
$(tClass).each(function(){
//get class names into classes array
var classes = $(this).attr('class').split(' '),
parentClass = '';
//search classes array for class that begins with 'cat'
for (var j=0; j<classes.length; j++) {
if (classes[j].match("cat")){
parentClass = classes[j];
}
}
//find subsubsub elements that have a class that begins with 'cat#sub'
var subs = $('[class*=' + parentClass + 'sub]');
//if there are sub elements, hide them too
if(subs){
subs.hide();
/*****************************************************
NEED HELP HERE !!!!!!!!!!
Need a way to reset all hide/show images icon
when 'parentClass' hide/show is clicked to close.
*****************************************************/
}
});
} else {
s = reveal_src;
}
//Change image src
$("#" + tID).attr('src', s);
});
});
To replicate: Toggle open all parents and subs, then close one of the parents, then reopen the parent. You'll notice that the +/- icon remains in it's previous state
jsFiddle link
You can find the img nodes for the subcategories under the current one and then change their src attr.
I've updated your jsfiddle: http://jsfiddle.net/nTyWv/12/
The code could be something like:
if(subs){
innerIcons = jQuery.find("a > img[id*="+tID+"sub]");
if (innerIcons) {
$(innerIcons).attr('src', s);
};
subs.hide();
}

Categories

Resources