Reference Individual Class Elements with 'this' - javascript

If I'm looping through different elements with the same class with mouseenter / mouseout events and I'm trying to incorporate the 'this' keyword so the JS only triggers on the element I'm hovering over. I can't get it to work though.
I've stripped out my attempts to use the 'this' keyword to make the code easier to read. How do I go about having it so that only the element being hovered over has the mouseenter and then mouseout events applied to it whilst looping through the elements?
I can't use a jQuery solution.
codepen pen: https://codepen.io/emilychews/pen/mMEEBw
Code is below:
JS
// declare variable for the CSS class
var menuItem = document.querySelectorAll('.menu-item');
//loop through CSS class to change background to red
function myMouseEnter() {
for (i = 0; i < menuItem.length; i++) {
menuItem[i].style.background = "red";
}
}
//loop through CSS class to change remove red background
function myMouseLeave() {
for (i = 0; i < menuItem.length; i++) {
menuItem[i].style.background = "none";
}
}
//event handler to add function on mouseenter
for (j = 0; j < menuItem.length; j++) {
menuItem[j].addEventListener('mouseenter', myMouseEnter, false)
}
//event handler to add function on mouseout
for (k = 0; k < menuItem.length; k++) { menuItem[k].addEventListener('mouseout', myMouseLeave, false)
}
CSS
.menu-item {padding: 10px;
font-family: arial;
}
HTML
<ul class="unclick--menuitems">
<li class="menu-item">About</li>
<li class="menu-item"><a href="//google.com">Projects</a</li>
<li class="menu-item">Contact</li>
</ul>

In your two functions, all you need to do is refer to this. In that context, this refers to the .menu-item event that you are currently hovering over.
Note that you'll also probably want to attach a handler for the <a> tag children, or else whenever you hover over them, the script will think you're leaving the <li>, and attempt to change the colours.
This can be done by checking the toElement and relatedTarget of the event in question, and then checking whether those are the parent <li> element.
All up, your code would look like this:
// declare variable for the CSS class
var menuItem = document.querySelectorAll('.menu-item');
// loop through CSS class to change background to red
function myMouseEnter() {
this.style.background = "red";
}
// loop through CSS class to change remove red background
function myMouseLeave() {
// prevent the 'mouseout' from affecting the <a> children
var e = event.toElement || event.relatedTarget;
if (e.parentNode == this || e == this) {
return;
}
this.style.background = "none";
}
// event handler to add function on mouseenter
for (j = 0; j < menuItem.length; j++) {
menuItem[j].addEventListener('mouseenter', myMouseEnter, false);
}
// event handler to add function on mouseout
for (k = 0; k < menuItem.length; k++) {
menuItem[k].addEventListener('mouseout', myMouseLeave, false);
}
.menu-item {
padding: 10px;
font-family: arial;
}
<ul class="unclick--menuitems">
<li class="menu-item">About</li>
<li class="menu-item">Projects</li>
<li class="menu-item">Contact</li>
</ul>
Note that the functions themselves don't have to loop through the menu items again ;)
Hope this helps! :)

Related

Accessing child elements in Javascript array via onclick (for loop)

I am looping through an array like this:
<% thoughts.docs.forEach(function(thought, i) { %>
<div class="square-box-container">
<div class="pyp-image-container">
<div class="image-overlay">
By default, element class name 'image-overlay' is hidden with display: 'none'. I am trying to create a function with an onclick event, so when user clicks on div 'square-box-container', the image overlay for that element only changes to display: 'block'.
Currently I have the below code but I think my inner loop in wrong, as when I click on a square box container, the image overlays for ALL the square box containers change to display: 'block', as opposed to that container overlay only. Can anyone advise what I'm doing wrong please?
var containerItems = document.getElementsByClassName("square-box-container");
var overlayItems = document.getElementsByClassName("image-overlay");
for (var i = 0; i < containerItems.length; i ++) {
containerItems[i].onclick = function() {
for (var i = 0; i < overlayItems.length; i ++) {
overlayItems[i].style.display = 'block';
}
}
}
I'm not very familiar with use of child nodes, is that what is required here? Thanks
If you want only the associated element to have its display changed, don't loop inside the click handler - and use let instead of var.
for (let i = 0; i < containerItems.length; i++) {
containerItems[i].onclick = function () {
overlayItems[i].style.display = 'block';
}
}
Another option is to omit the overlayItems collection entirely, and navigate from the clicked element instead.
for (const container of document.getElementsByClassName("square-box-container")) {
container.addEventListener('click', (e) => {
e.currentTarget.querySelector('.image-overlay').style.display = 'block';
});
}

How to remove CSS classes from the classList of each div element, and assign a desired CSS class to a div element, in an array of div elements?

I have a set of HTML buttons programmed with JavaScript. There's a class assigned to an array of HTML div elements, and the buttons are supposed to change that class.
Here's the code for one of the buttons:
a4.addEventListener('click', function()
{
//makes sure all the other buttons aren't chosen
var button = document.getElementsByClassName('unchosen');
for (var i = 0; i < button.length; i++)
{
button[i].classList.remove('chosen');
}
a4.classList.add('chosen');
//is supposed to assign the new css class to every plate div element and get rid of the undesired classes
const plates = document.querySelectorAll(".assay1Plate", ".assay2Plate", ".assay3Plate", ".assay4Plate");
for (var i = 0; i < 35; i++)
{
if (plates[i].classList.contains == "assay1Plate")
{
plates[i].classList.remove("assay1Plate");
console.log("Removed assay 1 plate class due to assay 4 click");
}
if (plates[i].classList.contains == "assay2Plate")
{
plates[i].classList.remove("assay2Plate");
}
if (plates[i].classList.contains == "assay3Plate")
{
plates[i].classList.remove("assay3Plate");
}
plates[i].classList.add("assay4Plate");
//I was going to use this to remove undesired classes from the div elements... but it doesn't really work
/*
for(var k = 0; k < classes.length; k++)
{
if (plates[i].classList.contains(classes[k]) && classes[k] != "assay4Plate")
{
plates[i].classList.remove(classes[k]);
console.log("Classes removed save 4");
}
}
*/
}
});
Console.log shows that classes are being ADDED to the classList of the elements, but it doesn't seem like they can be removed once they've already been added. Clicking the first button changes their classes, clicking the second changes it again, clicking the third changes it again, and so on.... but then clicking the first or second buttons again does nothing.

How do i style each li element at a time?

I am trying to style each <li> element at a time on click, not all at once. For each click, the first one, then on the second click, the next one and so on...
This code puts style on all li elements at once. How do I do it?
$("a").click(function() {
var menu = document.getElementsByTagName("li");
for (var i = 0; menu[i]; i++) {
$(menu).css("background", "red");
}
});
p {
color: red;
margin: 5px;
cursor: pointer;
}
p:hover {
background: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a>sdadsa</a>
<ul>
<li>asda</li>
<li>sadada</li>
<li>sada</li>
<li>asdad</li>
</ul>
You can use jQuery's .css() to check the css value of specified element
$("a").click(function() {
var menu = document.getElementsByTagName("li");
for (var i = 0; menu[i]; i++) {
// get element of current index
const menuElement = menu[i];
// if the first element's background is not red.
if ($(menuElement).css("background") !== "red") {
// set it red.
$(menuElement).css("background", "red");
// escape for loop
break;
}
}
});
You can use a variable that points to current li element which should change background on the next click. When the anchor tag is clicked we remove the background of previous li element and change the current element's background
<script>
let current = 0;
$("a").click(function () {
var menu = document.getElementsByTagName("li");
let prev = current-1;
if(prev==-1) prev = menu.length-1;
menu[prev].style.background = "none";
menu[current].style.backgroud = "red";
current = (current + 1)%menu.length;
});
</script>
One approach would be to add a class to do the styling.
When you click your element find the first <li> that doesn't have that class and add it to that one.
Adding and removing classes is typically easier than modifying and undoing inline style
$("a").click(function() {
$('li').not('.red-bg').first().addClass('red-bg')
});
.red-bg {background:red}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a>sdadsa</a>
<ul>
<li>asda</li>
<li>sadada</li>
<li>sada</li>
<li>asdad</li>
</ul>

<li> tags are not displayed when setting the style.display = none

I'm trying to create a toggle button that can set the tags with class adsetTarget of HTML tags "li" to be hidden or visible on click event.
During page load, the state of "li" tags are hidden. This is the code that is setting the initial page load event to be hidden. This is working correctly.
var appBanners = document.getElementsByClassName('adsetTarget'), i;
for (var i = 0; i < appBanners.length; i ++) {
appBanners[i].style.display = 'none';
}
Below is the code that is trying to set toggle button functionality. On clicking first time, it is displaying the content, but on clicking it again, the content is not hiding, can someone help.
var adsetTargets = document.getElementsByClassName('adsetTarget'), i;
for (var i = 0; i < adsetTargets.length; i ++) {
if (adsetTargets[i].style.display = 'none')
adsetTargets[i].style.display = '';
else
adsetTargets[i].style.display = 'none'; //this is not working, I believe
}
You have to change the following line:
if (adsetTargets[i].style.display == 'none')
Notice the double equals?
You can use this to make it senstive to any styling you apply to your elements.
It will remember the elements previous style and re-apply it(in theory heh)
function showhide() {
var adsetTargets = document.getElementsByClassName('adsetTarget'), i;
for (var i = 0; i < adsetTargets.length; i ++) {
if (adsetTargets[i].style.display == 'none') {
adsetTargets[i].style.display = adsetTargets[i].getAttribute('data-previous');
}
else {
adsetTargets[i].setAttribute('data-previous',adsetTargets[i].style.display);
adsetTargets[i].style.display = 'none'; //this is not working, I believe
}
}
}
<ul>
<li class="adsetTarget" style="display:table">abc</li>
<li class="adsetTarget" style="display:block">123</li>
<li class="adsetTarget" style="display:inline-block">def</li>
<li class="adsetTarget" style="display:inline-block">456</li>
</ul>
<input type="button" onclick="showhide()" value="click me">

Selections and radioing - JavaScript

I have a list like this:
<ul>
<li id="adm-thumb" onclick="javascript:addBanner('bowling.jpg');">
<div class="adm-tick"></div>
<img src="img/banners/bowling.jpg" /></li>
<li id="adm-thumb" onclick="javascript:addBanner('kcc.jpg');">
<div class="adm-tick"></div>
<img src="img/banners/kcc.jpg" /></li>
<li id="adm-thumb" onclick="javascript:addBanner('paintballing.png');">
<div class="adm-tick"></div>
<img src="img/banners/paintballing.png" /></li>
</ul>
<input id="bannername" type="text" />
When one item is clicked, the value inside the addBanner() will be added to the input field, however, I want one list to be selected (which is done by css to make it look like it has) when it is equal to the value of the input value. If the value is equals to the value in the addBanner value then the clicked item should have a red background.
e.g.
function addBanner(label)
{
var Field = document.getElementById('bannername');
Field.value = label;
if(Field.value != label)
{
// I have no idea what to put here
// assign a class to it? prevent others having the same when ONLY one must have the selected state
}
}
Something like a div button that acts like a radio button.
You can modify the addBanner function to include the list item that was clicked. Then inside the function remove the class or style from all list elements first. Then apply the required class to the clicked element.
The list items would become:
<li onclick="javascript:addBanner('bowling.jpg', this);"> .. </li>
The addBanner function now has two parameters, the second one being the list element that was clicked:
/* CSS */
.highlighted {
background-color: red;
}
/* Javascript */
function addBanner(label, clickedItem) {
var listItems = document.getElementsByTagName("li");
// clear all existing classes
for(var i = 0; i < listItems.length; i++) {
listItems[i].className = '';
}
document.getElementById('bannername').value = label;
clickedItem.className = 'highlighted';
}
There are already 2 flaws in your code:
1)
Field.value = label;
if(Field.value != label)
{
// this will never run, because you set the Field.value to the
// label one line above
}
2) when you use an id you can only use it once, else you should use a class in your 'li' elements.
Your question is very vague. You want the clicked 'li' element to have a red background and the rest not red?
You can do this by plain JS:
var lis= document.getElementsByTagName("li");
for (i = 0; i < lis.length; i++) {
var li = lis[i]; if(li.className == "adm-thumb") {
li.backgroundColor = "transparent";
}
}
this.backgroundColor = "red";
or jQuery:
$('adm-thumb').css("backgroundColor", "transparent");
$(this).css("backgroundColor", "red");
The way the question is worded, it's a bit hard to understand exactly what you mean, but the code below should hopefully give you the results you are after:
var liList = document.getElementById('list').childNodes;
for (var i = 0; i < liList.length; i++){
liList[i].addEventListener('click',changeColor,false);
}
function changeColor(e) {
var el = e.target;
var liList = document.getElementById('list').childNodes;
for (var i = 0; i < liList.length; i++){
liList[i].backgroundColor = "black";
}
el.style.backgroundColor = "red";
}
You will need to assign an id to the ul element, and you can remove the onClick calls from the li elements:
<ul id="list">
<li><div class="adm-tick"></div><img src="img/banners/bowling.jpg" /></li>
<li><div class="adm-tick"></div><img src="img/banners/kcc.jpg" /></li>
<li><div class="adm-tick"></div><img src="img/banners/paintballing.png" /></li>
</ul>
You may want to read up on Javascript event handling as well

Categories