javascript eventlistener on multiple objects - javascript

I made an EventListener for a few <div> elements, now i want do change the opacity on a child of this specific element to change if the EventListener is true on this specific element. How do I write that with jQuery or Javascript? I already wrote the pseudoquote, which I think should work. I have a problem to translate it to js.
var overLay = document.getElementsByClassName("overlay");
for (i = 0; i < overLay.length; i++) {
overLay[i].addEventListener("mouseover", mouseOver);
overLay[i].addEventListener("mouseout", mouseOut);
}
function mouseOver() {
document.getElementById("project_07").style.maxWidth = "20px"; //just for testing works!
/* PSEUDOCODE
if overlay[i] (mouseover === true) {
getChildElement of (this/ overlay[i]) // is an <img> element
and .style.opacity = ".8";
*/
}
function mouseOut() {
document.getElementById("project_07").style.maxWidth = "100%";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

With event listeners, you can use this to reference the current element. Because the handler will only react when during a mouseover event, you don't need to check it because it will always be true.
function mouseOver() {
this.querySelector("img").style.opacity = 0.8;
}
Then, if you want to clear the style change on mouseout, just add the same code to your mouseOut function.
function mouseOut() {
this.querySelector("img").style.opacity = 1;
}
Also, if you are only modifying the style of child elements, you could solve this with just css.
.overlay:hover img {
opacity: .8;
}

When event is fired you can access the event prameters. It goes to function as n attribute.
One of properties of the event is target - element that fireв event.
function mouseOver(e) {
e.target.querySelector('img').style.maxWidth = "20px";
}
Try to console.dir(e.target) and research it.

I will simply suggest:
1.assign class to all divs you want to have child change opacity
let's say myClass
$('.myClass').children().on('mouseenter', function(){
$(this).css('opacity', '0.8');
});

Related

Removing an element from a node without removing the associated event?

I have been working on an html/css/javascript 'etch-a-sketch' style project.
In a nutshell I have a grid of div elements with a mouseenter event:
const fillInGrid = document.querySelectorAll(".gridSquares");
fillInGrid.forEach((div) => {
div.addEventListener('mouseenter', (e) => {
div.style.backgroundColor = 'black';
});
});
In the project I have a reset button that removes the child elements from the grid and replaces them with new divs, two prompts where a number of rows and columns specified by the user which then generates a new grid:
const resetButton = document.querySelector("#reset");
resetButton.addEventListener('click', (e) => {
const resetEvent = document.getElementById('container');
while (resetEvent.lastElementChild) {
resetEvent.removeChild(resetEvent.lastElementChild);
};
newGrid();
}
);
However, after clicking reset and choosing dimensions for a new grid, the grid is generated but the grid loses responsiveness to the mouseenter event because I'm assuming the event is being removed along with the divs, is there a way to re-add the event or a method alternative that can remove the divs without the associated event?
A link to a codepen demonstrating the issue: https://codepen.io/MaBuCode/pen/eYpjwOV
Instead of adding multiple event listeners on the child elements, you can add a single event listener at the containing element. This way, your code will become more performant and you will also get to catch any event that gets triggered on the dynamically (newly created) elements.
You will need to replace the mouseenter event with the mouseover event, that supports bubbling.
Here's the code to add and replace the mouseenter event:
// // One event listener to rule them all:
document.getElementById("container").addEventListener('mouseover', (e)=>{
if ( e.target.classList.contains('gridSquares')){
e.target.style.backgroundColor = 'black';
}
});
You can now get rid of the individual div event listener:
fillInGrid.forEach((div) => {
div.addEventListener('mouseenter', (e) => {
div.style.backgroundColor = 'black';
});
});
Codepen Demo
Tip: I have also refactored the ’gridCreator' function to reduce the number of appendChild operations, and instead replaced it with a simple string concatenation to make the code more performant:
function gridCreator(gridSize) {
let content = "";
for (let i = 0; i < gridSize; i++) {
content += "<div class='gridSquares'></div>";
}
document.getElementById("container").innerHTML = content;
}
By using the approach above, you can also omit the code that removes the .container child elements in the resetButton code.

Accessing items in Javascript Node List to alter image

I am trying to create the same effect of CSS Hover but with Javascript code (for the purpose of learning Javascript and for future use). So on mouseover, I would like the individual image to increase opacity.
The code I have written below does not work. Please see comments for explantion regarding what I am trying to do;
<script>
//gets all img tags (qu.20)
var images = document.getElementsByTagName("img")
// Create new element with id "newNode" for the individual node to go into
var node = document.body.createElement("newNode")
// Add the new element into the html document
document.body.appendChild(newNode)
// Attach var i to the individual nodes and set src of new element as that node
function overImage () {
for (var i=0; i<images.length; i++) {
document.getElementById("newNode")
document.body.newNode.src = images.item(i)
}
}
// function to create a new class with same attributes as original when mouse leaves image
function leaveImage () {
for (var i=0; i<images.length; i++) {
document.getElementById("newNode")
document.body.newNode.src = images.item(i)
document.body.newNode.className = " leave"
}
}
</script>
<html>
<img src="image1.gif" onmouseover="overImage()" onmouseout="leaveImage()" alt="image" />
<img src="image2.gif" onmouseover="overImage()" onmouseout="leaveImage()" alt="image" />
</html>
<style>
img { opacity:0.5; }
#newNode { opacity:1; }
#newNode.leave { opacity:0.5; }
As an alternative, this code works but only on all images (ie. they all change opacity together, not individually.
<script>
function overImage () {
var selectImage = document.getElementsByTagName("img")
for (var i=0; i<selectImage.length; i++) {
selectImage[i].className = " over"
}
}
function leaveImage () {
var selectImage = document.getElementsByTagName("img")
for (var i=0; i<selectImage.length; i++) {
selectImage[i].className = ""
}
}
</script>
<style>
img { opacity:0.5; }
.over { opacity:1; }
</style>
Answers in Javascript only please with explanations. No jquery
You can do this in a much simpler manner, check this example:
var f = function(e) {
// the event target, can be any element in the page at this point
var t = e.target;
// check if the event target is an img element
if(t.tagName.toLowerCase() == 'img') {
// then toggle its active class
t.classList.toggle('active');
}
}
// add listeners to the window (or on whatever image container you have)
addEventListener('mouseover', f /* call this function f on mouseover */, false);
addEventListener('mouseout', f, false);
img { opacity: .5; }
.active { opacity: 1; }
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
This code is going to work no matter how many images you add after this. It eliminates for you to add calls to your JS functions (whose names you may choose to change) to the HTML, the need for messing with the DOM from JS, the need for looping in the JS. And as far as the CSS is concerned, it's not using ids for styling, so it's avoiding specificity issues.
Your issue appears to be right at the top, document.body.createElement("newNode") will give you a TypeError: undefined is not a function. The createNode method is on the #document node, not a HTMLElement.
Next, you create nodes by tag name, there is no such tag <newNode>, maybe you meant to create an <img>
var node = document.createElement("img");
Now you need to assign the id attribute to it,
node.setAttribute('id', 'newNode');
Next, you have to append node to your document tree (you're currently trying to append an undefined variable newNode)
document.body.appendChild(node);
Finally, your two functions overImage and leaveImage have several problems of their own;
They are performing document.getElementById but not remembering the result, instead trying to go through the DOM tree in an unusual way and also you're trying to assign a node as a src, when you probably want to assign a String
// outside loop
var node = document.getElementById("newNode");
// inside loop
node.src = images.item(i).src;
They loop over all of images each time, meaning you will always finally end up with node's src pointing at the value from the last item in images
Try linking up these listeners using foo.addEventListner(type, event_handler) where foo is a reference to each node you want to attach the event_handler to. This will let you access the mouseover or mouseout event in more detail, especially if event_handler looks at it's first argument which will be the event itself, or this which will be the node which invoked the handler.
Always check your console as the first step in debugging, it'll usually let you quickly narrow down your issue to the exact line with the problem

Cancel :active element styling

I have DOM elements with :active CSS styling. If a user makes a click, but never releases the click, I want to be able to cancel the :active styling through Javascript.
I have tried doing document.activeElement.blur() but that doesn't work when the user does not release the click. (See fiddle here.)
How can I force blur an element if the user doesn't release their click?
#bobdye's example doesn't work because <div> elements aren't "focusable" by default.
You can force this behaviour by assigning a tabindex property to the div, here is a fiddle.
HTML
<div class="defocus">.::.:.:.::.</div>
<div class="defocus">:..:.:.:..:</div>
<div class="defocus">.::.:.:.::.</div>
You add the class="defocus" attribute to any element that needs to blur after x seconds.
CSS (relevant)
div:active {
color:lightcoral;
}
JavaScript
(function () {
window.addEventListener("load", function () {
var seconds = 0.15 * 1000;
var defocused = document.getElementsByClassName("defocus");
for (var i = 0, l = defocused.length; i < l; i++) {
var el = defocused[i];
el.style.outline = 0; //optional
el.setAttribute("tabindex", -1);
el.addEventListener("mousedown", blur);
}
function blur(e) {
var el = e.target;
setTimeout(function (el) {
el.blur();
}, seconds, el);
}
});
})();
First we wrap this function in a seaf just as a commodity (it will prevent the blur function and variables from being accessible).
Then we get all the elements with a defocus class.
Then we iterate over them.
First we eliminate the focus outline some browsers use because it looks ugly in a div, but it's up to you.
Then we set a tabindex="-1". Using -1 as an index prevents it from acting as a tab break point but allows it to recieve focus and blur events.
Finally we add the blur() function to the mousedown event which will defocus de element after x seconds.
Then we define the blur() function which will take care of defocusing the element with a setTimeout().
That's it, hope it helps!
Note: I don't particularly care for the bounty, keep your rep!
Note: Thanks to #Adam for pointing out that seaf's variables need the var prefix to prevent them from being global.
This Fiddle a simple example of canceling the active state if the user holds the mouse down for more than 500ms.
It uses a link:
<a id="testlink" href="#">Click this</a>
styled to be red if active, and this Javascript:
var lnk = document.getElementById('testlink');
var mousedown = false;
var timerId = null;
lnk.addEventListener('mousedown', function(e) {
mousedown = true;
timerId = window.setTimeout(function() {
if (mousedown) {
lnk.blur();
}
}, 500);
});
lnk.addEventListener('click', function(e) {
mousedown = false;
window.clearTimeout(timerId);
});
Obviously not customized for your particular case, but a "proof of concept".
to be added to other answers, you may use a transition (delayed or not):http://codepen.io/anon/pen/LEXZGB
*:active {
background: red;
filter:blur(5px);
transition: filter 3s 1s;
}
<script src='http://s.codepen.io/assets/libs/prefixfree.min.js'></script>
see me blured if you click too long.

Attaching Click Event to DIV Using jQuery Library

I am aware I can use the click function to attach an event to the DIV element but for some reason it is not working for me. Here is how I am creating the DIV element.
function createColorSwatchDiv(color) {
var colorSwatchDiv = $("<div>");
var image = $("<img>");
image.attr("src",color.imageURL);
var label = $("<label>");
label.text(color.title);
colorSwatchDiv.append(image);
return colorSwatchDiv;
}
Then I try to attach the click event like the following:
// run a loop and build the grid layout
for(index = 0; index < colors.length; index++) {
var colorSwatchDiv = createColorSwatchDiv(colors[index]);
// attach the event
colorSwatchDiv.click(function(){
alert('hello world');
});
colorsSection.append(colorSwatchDiv);
}
// add to the dom
$("#color .imageChartOption").after(colorsSection);
But it does not work and no click event is been attached.
following is the code
var $newdiv1 = $("<div id='object1' onClick=Test()>Hello</div>");
$("body").append($newdiv1);
function Test()
{
alert("Clicked");
}
OR
$newdiv1.on('click',function(){alert("hello");});
since you have created the div in a jQuery wrapper you don't need to wrap it again here $(colorSwatchDiv).click(.... Also, are you sure that the colorSwatchDiv variable is referencing the dom element and not the in memory element? Can you apply a class or anything to the elm in the dom?

How do I remove :hover?

I have a small problem with a script.
I want to have a default action on :hover for clients with Javascript disabled, but for those with Javascript enabled I want another action (actually... same action, but I want to add a small transition effect).
So... How can I do this? I am using jQuery.
Apply two classes to the relvant element. one contains the hover behaviour, and one contains all the other styling.
You can then use the jquery
$(element).removeClass('hover');
method to remove the class with the hover behaviour and then apply whatever you want using
$(element).bind('mouseover', function () { doSomething(); });
$(element).bind('mouseout', function () { doSomething(); });
How about putting the :hover fall-back in a stylesheet that is only loaded if javascript is disabled?
<noscript>
<link href="noscript.css" rel="stylesheet" type="text/css" />
</noscript>
Here is a solution without hack classes:
CSS:
a {color: blue;}
a:hover {color: red;}
jQuery (uses jQueryUI to animate color):
$('a').hover(
function() {
$(this)
.css('color','blue')
.animate({'color': 'red'}, 400);
},
function() {
$(this)
.animate({'color': 'blue'}, 400);
}
);
demo
I think the best approach would be to leave the :hover behavior as a fall-back for non-javascript users and then use JQuery to create mouseover and mouseout event handlers to create a different effect for javascript-enabled users.
JQuery Javascript Library - Events/mouseover
It's a very old question but I feel the urge to tell that modernizr provides a very good way to implement these kind of fallbacks.
Just include modernizr in the head and you can do these:
.no-js a:hover {
set background color and stuff like that
for cases when no javascript is present
}
On the other hand if you want to do this the other way and only set css when js is present
.js a:hover {
set background color to default
and the text decoration
}
It is more or less the same solution as adding a hover tag to the markup, but a little more robust.
I HAVE FOUND YOUR SOLUTION
basically you start out by redefining what you did with the css hover.
(naturally you would do this by dynamically pulling the information from the style)
then do whatever you want to in jquery with mouseover/mouseout events
this allows you to keep the :hover event in your css because jquery is binding your original styles to the element. In essence disabling the :hover event.
if your css is:
a.class {
background-color: #000000;
background-position: 0 0;
}
a.class:hover {
background-color: #ffffff;
background-position: 100% -50px;
}
your jquery would be somthing like:
jQuery("a.class").each(function () {
var oldBackgroundColor = jQuery(this).css("backgroundColor");
var oldBackgroundPosition = jQuery(this).css("backgroundPosition");
jQuery(".class").css({
'backgroundColor':oldBackgroundColor,
'backgroundPosition':oldBackgroundPosition
});
})
.bind("mouseover", function() {
doSomething();
})
.bind("mouseout", function() {
doSomething();
})
You can redraw element after click
function redraw(element) {
if (!element) { return; }
let n = document.createTextNode(' ');
let disp = element.style.display; // don't worry about previous display style
element.appendChild(n);
element.style.display = 'none';
setTimeout(function(){
element.style.display = disp;
n.parentNode.removeChild(n);
}, 100); // you can play with this timeout to make it as short as possible
}
You can globally enable behavior across the entire document by using a single css rule, and then disable that rule in one statement in javascript, while installing the new event handler.
Add a class to your html body tag:
<html>
<body class="use-hover">
...
Default behavior in your css, let's say to bold links on hover:
body.use-hover a:hover
font-weight: bold
And in your js, when run will remove the default behavior and do something else:
$(function() {
$('body').removeClass('use-hover');
$('a').live('mouseover', function() {
// Do something when hovered
}).live('mouseout', function() {
// Do something after hover is lost
});
});
You could strip all :hover style rules from document.styleSheets.
Just go through all CSS styles with JavaScript and remove all rules, which contain ":hover" in their selector. I use this method when I need to remove :hover styles from bootstrap 2.
_.each(document.styleSheets, function (sheet) {
var rulesToLoose = [];
_.each(sheet.cssRules, function (rule, index) {
if (rule.selectorText && rule.selectorText.indexOf(':hover') > 0) {
rulesToLoose.push(index);
}
});
_.each(rulesToLoose.reverse(), function (index) {
if (sheet.deleteRule) {
sheet.deleteRule(index);
} else if (sheet.removeRule) {
sheet.removeRule(index);
}
});
});
I did use underscore for iterating arrays, but one could write those with pure js loop as well:
for (var i = 0; i < document.styleSheets.length; i++) {}
Vanilla JS version of Mikael Lepistö's answer
for (var i = 0; i < document.styleSheets.length; i++) {
var sheet = document.styleSheets[i];
var rulesToLose = [];
for (var j = 0; j < sheet.cssRules.length; j++) {
var rule = sheet.cssRules[j];
if (rule && rule.selectorText && rule.selectorText.indexOf(':hover') >= 0) {
rulesToLose.push(j);
}
}
// Iterate backwards to prevent pointing to the wrong index while sheet rules get deleted
for (var k = rulesToLose.length - 1; k >= 0; k--) {
sheet.deleteRule(rulesToLose[k]);
}
}

Categories

Resources