I'm trying to change the background image of a div when a user hovers over and clicks it. I'm stuck on limiting the images from changing to ONLY the element on which the user is hovering/clicking. In this example, all of the buttons will change when one div is hovered on/clicked. This is something I'm trying to replicate that's already working in jQuery. I'm guessing it's possible to use "this" but all of the ways I've tried so far result in errors.
Bonus points for anyone who cal tell me why the alert happens on page load in Firefox but not IE or Chrome
JavaScript
var buttons = document.getElementsByTagName('div');
var i;
function iconDown(e) {
for (i=0; i<buttons.length; i++) {
buttons[i].style.backgroundPosition = '0px -61px';
}
}
function iconUp(e) {
for (i=0; i<buttons.length; i++) {
buttons[i].style.backgroundPosition = '0px -122px';
}
}
function iconOver(e) {
for (i=0; i<buttons.length; i++) {
buttons[i].style.backgroundPosition = '0px -122px';
}
}
function iconOut(e) {
for (i=0; i<buttons.length; i++) {
buttons[i].style.backgroundPosition = '0px 0px';
}
}
function processAction() {
alert("Working!");
}
function Init () {
for (i=0; i<buttons.length; i++) {
if (document.addEventListener) { // all browsers except IE before version 9
buttons[i].addEventListener ("mousedown", iconDown, false);
buttons[i].addEventListener ("mouseup", iconUp, false);
buttons[i].addEventListener ("mouseover", iconOver, false);
buttons[i].addEventListener ("mouseout", iconOut, false);
buttons[i].addEventListener("click", processAction, false);
}
else { // IE before version 9
buttons[i].attachEvent ("onmousedown", iconDown);
buttons[i].attachEvent ("onmouseup", iconUp);
buttons[i].attachEvent ("onmouseover", iconOver);
buttons[i].attachEvent ("onmouseout", iconOut);
buttons[i].attachEvent("onclick", processAction);
}
}
}
Init();
CSS
.btn {width:100px; height:61px; float:left;}
#BackImg {background: url('images/Back.gif') no-repeat 0px 0px;}
#NextImg {background: url('images/Next.gif') no-repeat 0px 0px;}
HTML
<DIV class="btn" ID="BackImg"></DIV>
<DIV class="btn" ID="NextImg"></DIV>
You don't need any javascript for this. Just use css.
.specialClassyClass{
/*default background position*/
}
.specialClassyClass:hover{
/*hover state background position*/
}
.specialClassyClass:active{
/*mouse down background position*/
}
For the clicky stuff:
var whatever = function(el, ev, handler){
el.attachEvent?
el.attachEvent(ev, handler):
el.addEventListener(ev, handler, false);
}
whatever(button[i], 'click', processAction);
You can use this:
function processAction(e) {
var active = document.querySelector('.active'); // get currently active button
if(active != undefined)
active.className = "btn"; // remove active class
e.target.className = 'btn active' // add active class to clicked element
}
then your css can be something like:
.btn {width:100px; height:61px; float:left;background: orange;}
.active {background: red;}
http://jsfiddle.net/NXVv7/
Related
I am coding a simple navigation bar for a project that has four sections, and I made it interactive enough to have a specific color when hovering/clicking on a section and then it returns back to its original color after clicking.
But what if I want the selected section to still be colored/highlighted when a user is viewing it?
So if the hovering color is coded blue, i want the section in the Navbar to still be blue when a user has selected it, and then changes when a user selects another section. Here's my code so far.
// The mouse hover functiona and commands. Here we specificy the color of the buttons/mouse
// when the user clicks on them, there's a color for hovering/clicking
// and a color for leaving the button
function mouseOver () {
let anchor = document.getElementsByTagName('a');
for (i = 0; i < anchor.length; i++) {
anchor[i].addEventListener('mouseover', function handleMouseOver() {
event.target.style.backgroundColor = "#72a6ca";
event.target.style.color = "#fff";
})
//the color returns to its normal state after clicking away
anchor[i].addEventListener('mouseout', function handleMouseOut() {
event.target.style.backgroundColor = "rgb(220, 220, 220)";
event.target.style.color = "black";
})
}
}
and here is my navbar display code
function navBarStyle () {
let anchor = document.getElementsByTagName('a');
let styles = `
display: flex;
flex-direction: row;
align-items: stretch;
color: #000;
text-decoration: none;
margin: 0 0.5em 0 0.5em;
padding: 0.5em;
background-color: rgb(220, 220, 220);
font-size: large;
transform:translateX(-0.5em);
`;
for (i = 0; i < anchor.length; i++) {
anchor[i].setAttribute('style', styles);
} }
if i was vague enough i am sorry, but any help would be appreciated to put me on the right track
Firstly, a note for your current implementation. It works and it is pretty well coded. But for this thing browsers offer native functionality using the :hover selector and it would be better to use than to reinvent it.
I don't have your HTMl but you would most likely need to add a class to each 'a' tag in the nav, something like this:
<nav>
Link 1
Link 2
</nav>
and then you would need a style tag in the head (or better, external css)
<head>
...
<style>
.nav-link {
background-color: 72a6ca;
color: #fff;
}
.nav-link:hover {
background-color: rgb(220, 220, 220);
color: black;
}
</style>
</head>
As for the current section, your best bet would be to use https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
See here for an example: Intersection observer API scroll aware navigation
or this codepen: https://codepen.io/mishunov/pen/opeRdL
Using IntersectionObserver you can detect when the user scrolls in/out of the section. You can toggle another class on and off of the related nav-link then. For example - say you toggle the .current class, your style could look like this to style both cases (hovering and currently scrolled) in 1 place:
.nav-link:hover,
.nav-link.current {
background-color: rgb(220, 220, 220);
color: black;
}
You can make a class named active like this
.active {
backgroundColor: #72a6ca;
color: #fff;
}
and assign it to each anchor that's clicked(or hovered), simultaneously remove .active from the other anchors
let anchors = document.getElementsByTagName('a');
for (let anchor of anchors) {
anchor.addEventListener('mouseover', function handleMouseOver() {
const target = event.currentTarget;
if (target.classList.contains('active')) {
target.classList.remove('active')
} else {
[...anchors].forEach((anchor) => anchor.classList.remove('active'))
target.classList.add('active')
}
})
}
If you want to give the class active to the anchors in viewPort use this code:
const anchors = document.getElementsByTagName('a');
const isInViewport = el => {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <=
(window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
const run = () =>
anchors.forEach(item => {
if (isInViewport(item)) {
item.classList.add('active');
}
});
// Events
window.addEventListener('load', run);
window.addEventListener('resize', run);
window.addEventListener('scroll', run);
I'm trying to add new CSS class to HTML body but only after a button/link is clicked. I have included the code along with some errors information.
I have already created a function that can trigger an alert after the button/link is clicked. it's working perfectly but the ".classList.add " method/option is not taking any effects.
<html>
<head>
<style>
.addBGoverlay {background-color: gray;}
.bG {background-color: white;}
</style>
</head>
<body class="BG">
<a class="dash-menu mega-menu-link " role="button" href="#"><span class="mega-indicator"> navButtn</span></a>
<script type="text/javascript">
var X = document.getElementsByClassName('dash-menu');
var xLength = X.length;
var bg = document.getElementsByTagName('body');
function startAction() {
alert('This a popUp');
bg.classList.add("addBGoverlay");
}
for (var i = 0; i < xLength; i++) {
X[i].addEventListener('click', startAction, false);
}
</script>
</body>
</html>
when I inspect it in chrome it gives me an error "Uncaught TypeError: Cannot read property 'add' of undefined
at HTMLAnchorElement.startAction" and the below line is highlited in yellow color "bg.classList.add("addBGoverlay");"
getElementsByTagName() method will give you a collection of DOM elements. Since this collection don't have a classList property it will fail.
You can fix it by using the below code
bg[0].classList.add("addBGoverlay");
You can also use document.body instead of document.getElementsByTagName('body'). First one (document.body) give you the body object and second one will give you a collection object
For switch to previous state
Approach 1
function startAction() {
let body = document.body ;
if(body.classList.contans("addBGoverlay")){ // body.classList.contans() method will give a Boolean return value
body.classList.remove("addBGoverlay");
}else{
body.classList.add("addBGoverlay");
}
}
Approach 2
var hasBGOverlay = false;
var body = document.body ;
function startAction() {
if(hasBGOverlay){
body.classList.remove("addBGoverlay");
}else{
body.classList.add("addBGoverlay");
}
hasBGOverlay = !hasBGOverlay; // In each call state variable value will update with inverse value
}
Hope this helps
Try with Add ID attribute to body tag.
ie:
<body class="bg" id="dg_body">
js
var bg = document.getElementById('dg_body');
and update css order :
.bG {background-color: white;}
.addBGoverlay {background-color: gray;}
will work.
Change your code from :
bg.classList.add("addBGoverlay");
To:
bg.className += "addBGoverlay";
Hope it helps!
Enclosing it under window.load should solve it as it ensures that the DOM is ready before you try to fetch the elements.
window.onload(function() {
var X = document.getElementsByClassName('dash-menu');
var xLength = X.length;
var bg = document.getElementsByTagName('body');
function startAction() {
alert('This a popUp');
bg.classList.add("addBGoverlay");
}
for (var i = 0; i < xLength; i++) {
X[i].addEventListener('click', startAction, false);
}
});
.addBGoverlay {
background-color: gray;
}
.bG {
background-color: white;
}
<a class="dash-menu mega-menu-link " role="button" href="#"><span class="mega-indicator">navButtn</span></a>
Just change
var bg = document.getElementsByTagName('body')[0];
This will fix the error.
It must resolve your's problem.
you no need to get an element for the body. Document have that one. So
just concatenate the new class.
function startAction() {
alert('This a popUp');
document.body.className += "addBGoverlay";
}
so I'm trying to append image src to a div when you click on it...so far I've written it like this and it doesn't seem to work, no error reports, no idea what's going on. The image is of a class .card (there's 15 of them), and I want to append to the div only if the border is gray, you click once to select the card (changing the border) and then click again to paste the selected card onto the div...the div is called .picks. I just want to display the image src as text on my page. thanks for the help
$(".card").click(function() {
console.log("click");
if($(this).css('border')==="4px solid gray") {
var cardname = $(this).attr('src');
$(".picks").append(cardname);
if(pick<15) {
pick++;
}
else {
booster++;
pick=1;
}
}
else {
$(this).css('border', '4px solid gray');
}
});
The problem is that you rely on result of css("border") while it's not what you expect: e.g. Chrome will retrieve border styles as "4px solid rgb(128, 128, 128)".
Instead set CSS class selected and check if the card has this class or not:
$(".card").click(function () {
if ($(this).hasClass('selected')) {
var cardname = $(this).attr('src');
$(".picks").append(cardname);
if (pick < 15) {
pick++;
} else {
booster++;
pick = 1;
}
} else {
$(this).addClass('selected');
}
});
Demo: http://jsfiddle.net/1o7tgs5j/13/
In general as the rule of thumb, avoid using $.fn.css method for styling, not only this is very obtrusive but also error prone approach. In most cases usage of addClass/removeClass brings much more flexibility.
You should be using
if($(this).css('border')==="4px solid rgb(128, 128, 128)")
{
....
}
But i will suggest you to do it this way...
$(".card").click(function () {
console.log("click");
if ($(this).hasClass("clicked")) {
var cardname = $(this).attr('src');
$(".picks").append(cardname);
if (pick < 15) {
pick++;
} else {
booster++;
pick = 1;
}
} else {
$(this).css('border', '4px solid gray').addClass("clicked");
}
});
Working Fiddle
<div id="button">
Click me
</div>
<div id=item1> //loads with a dashed border
</div>
<div id=item2> //loads with a solid border
</div>
<div id=item3> //loads with a solid border
</div>
Script part:
var eventNext = document.getElementById("button");
eventNext.addEventListener("click", move, false);
function move()
{
}
What would I put in the move function to get the next div item that does not have a dashed border, and make it dashed, and current item's border to solid? (if there is a next item)?
var eventNext = document.getElementById("button");
eventNext.addEventListener("click", move, false);
function move() {
if( eventNext ) {
if( eventNext.id !== 'button' ) {
eventNext.className = 'solidBorder';
}
eventNext = eventNext.nextElementSibling;
if( eventNext ) {
eventNext.className = 'dashBorder';
}
}
}
.dashBorder {
border: 2px dashed blue;
}
.solidBorder{
border: 2px solid blue;
}
or with jquery
var eventNext = $("#button").bind("click", move);
function move() {
if( eventNext.length ) {
if( eventNext.attr('id') !== 'button' ) {
eventNext.attr( 'class', 'solidBorder' );
}
eventNext = eventNext.next();
if( eventNext.length ) {
eventNext.attr( 'class', 'dashBorder' );
}
}
}
if you need to support browsers that dont support nextElementSibling, use this functoin instead.
function next( elem ) {
while( (elem = elem.nextSibling) && (elem.nodeType !== 1) );
return elem;
}
Here's one way with jQuery, if using this library happens to be an option for you:
First, give each div which can become dashed, a "marker class"
<div id="item1" class="itemWhichCanBeDashed">
//loads with a dashed border
</div>
<div id="item2" class="itemWhichCanBeDashed">
//loads with a solid border
</div>
<div id="item3" class="itemWhichCanBeDashed">
//loads with a solid border
</div>
Then create a dashed border style:
<style type="text/css">
.dashed { border-style: dashed; }
</style>
Then, to dash the next div that's not already dashed:
$("div.itemWhichCanBeDashed:not(.dashed):first").addClass("dashed");
This selects all divs with the class itemWhichCanBeDashed, but does not have the dashed class attached, then takes the first one, then adds the class dashed
If you want the first div to already be dashed, then just render it with the dashed class.
I'm not sure exactly what the requirement of making the current div solid is, but it should be a simple extension of this.
EDIT
To host jQuery in your project, you can link to it from Google:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
If your user has recently visited a site that was linking to the same file, it'll likely be cached. If not, it's only about a 92K download.
This would be easier if you used a js framework like jquery. It's as simple as adding a reference to your head like this:
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
Using jquery, the code would be
var lastChanged;
$(document).ready(function() {
lastChanged = $('#item1');
$('#button').click(function() {
$(lastChanged).css("border", "1px solid #000");
$(lastChanged).next().css("border", "1px dashed #000");
lastChanged = $(lastChanged).next();
});
});
Here it is on jsfiddle - http://jsfiddle.net/JKYue/
see if this help to get you started
<button onclick="nextItem()">Click me</button>
var nextItem = (function() {
var arr_item, arr_len, intIdx, currentItemInt;
arr_item = ["item1", "item2", "item3"];
arr_len = arr_item.length;
intIdx = -1;
currentItemInt = "";
return function(){
for (var j= 0; j < arr_len; j++) {
var elm = document.getElementById(arr_item[j]);
var os = (elm.currentStyle) ? elm.currentStyle["borderStyle"] : window.getComputedStyle(elm,"").getPropertyValue('border-top-style');
if(os == "dashed"){
intIdx = j;
//alert(j)
currentItemInt = arr_item[j + 1];
}
}
// alert(arr_item[intIdx])
if(intIdx < arr_item.length-1){
document.getElementById(arr_item[intIdx]).style.border = "white dashed";
document.getElementById(currentItemInt).style.border = "black dashed";
}
}
}());
I'ld like to change the "imgTag.style.border='5px solid #FF00FF'" to black when the mouse is over an image.
This is my JavaScript:
javascript:for(i=0;i<document.getElementsByTagName('img').length;i++)
{
var imgTag=document.getElementsByTagName('img')[i];
imgTag.style.border='5px solid #FF00FF';
imgTag.title='';
imgTag.onclick=function()
{
return !window.open('http://www.example.com/#/'+this.src);
}
}
void(0)
How can it be done?
Thanks
Frank
You need to bind handlers to the mouseover and mouseout events to change the image's border color:
var imgs = document.getElementsByTagName('img');
for(var i = 0; i < imgs.length; ++i) {
imgs[i].onmouseover = function() {
this.style.borderColor = '#000';
};
imgs[i].onmouseout = function() {
this.style.borderColor = '#f0f';
};
}
For example: http://jsfiddle.net/bNk4Y/
Not sure what's wrong with the code you have, but if i understand your question correctly, this should do it:
HTML:
<img src="" >
<img src="">
...
JS:
var imgs = document.getElementsByTagName("img");
for(i=0;i<imgs.length;i++)
{
imgs[i].onmouseover = function() {this.style.border="1px red solid";};
}
Note, however, that this can easily be achieved with CSS as well, which is a better practice - in case users have JS disabled, etc
img:hover {
border: 1px red solid;
}