Onmouseover/out - javascript

Two issues I am having.
The mouseover function is very FAST and it's definitely not working properly. I made a separate function for the onmouseout state, but it didnt help.
The class changes properly, however it stays changed and doesn't go back to it's original class. It depends if the link is on the selected page. Any help would be GREATLY appreciated
JAVASCRIPT:
function changeRollover(rollover) {
var rollItems = document.getElementById(rollover);
var rollLinks = rollItems.getElementsByTagName('a');
var noOfLinks = rollLinks.length;
for (var r = 0; r < noOfLinks; r++) {
var normalText = rollLinks[r].innerHTML;
var rolloverText = rollLinks[r].title;
var rolloverItem = document.getElementById(rollover);
rolloverItem.innerHTML = "<a href='#' title='" + normalText + "'>" + rolloverText + "</a>";
rolloverItem.class = rollover + "rollover";
}
}
HTML:
<div class="nav">
<ul id="NavItems">
<li id="item0" class="selected" onClick="changeClass(this.id)"
onmouseover="changeRollover(this.id)">
Collections
</li>
<li id="item1" onClick="changeClass(this.id)"
onmouseover="changeRollover(this.id)">
<a href="#" title="Shop Everything" >All Jewlery</a>
</li>
<li id="item2" onmouseover="changeRollover(this.id)"
onClick="changeClass(this.id)">
As Seen On
</li>
<li id="item3" onmouseover="changeRollover(this.id)"
onClick="changeClass(this.id)">
Collaborations
</li>
<li id="item4" onmouseover="changeRollover(this.id)"
onClick="changeClass(this.id)">
Designer Pop Ups
</li>
</ul>
<div class="shipping">
<a href="#">start your free orders today<br>
*** click here for more information ***</a>
</div>
</div>
<!-- .nav -->

The effect you want (dubious from a usability perspective, but that aside) is better achieved using some simple CSS:
#NavItems .hover {
display: none;
}
#NavItems:hover .hover {
display: inline;
}
#NavItems:hover .normal {
display: none;
}
Which requires markup like this:
<ul id="NavItems">
<li id="item0">
<a href="#">
<span class="normal">Collections</span><span class="hover">Shop Trends</span>
</a>
</li>
</ul>

Depending on your browser compatability requirements, I'd recommend using onmouseenter instead as the trigger for your function.
DOM Events - Browser Compatability
But for one thing, you're missing an onmouseout function that can reset the class for you. Once you attach a class to an element, it has to be removed manually as well if you want it to go away depending on what the user does. So create something like a resetRollover function, like the one below, and attach an onmouseout DOM listener that fires that function:
function resetRollover(rollover) {
var className = document.getElementById(rollover).className;
document.getElementById(rollover).className = className.substring(0, indexOf(' rollover'));
}

The problem is your onmouseover handler is on the lis. When the mouse hovers over the <a>s in the <li> and "reenters" onmouseover of the <li> is triggered again.
Example here: this is the same code as yours, I added some colors. If you move the mouse only on the black part (the <li>), the rollover happens as desired. But when you move the mouse on the green part (the <a>s).
As a solution, you can either handle the rollover on the <a>s or change your basic design (see #Thomas' answer)

Related

Change div content on mouse hover with default content fallback

I've implemented the accepted answer to Change div content based on mouse hover on different divs across a lot of links, so I don't really want to go with another solution if it can be avoided. I'm trying to figure out one more piece of the puzzle though...
I can't seem to get it to where it defaults back to the original text of the content div when not hovering over an item.
<div id="content">
Stuff should be placed here.
</div>
<br/>
<br/>
<br/>
<ul>
<li onmouseover="hover('Apples are delicious')">Apple</li>
<li onmouseover="hover('oranges are healthy')">Orange</li>
<li onmouseover="hover('Candy is the best')">Candy</li>
</ul>
<script>
function hover(description) {
console.log(description);
document.getElementById('content').innerHTML = description;
}
</script>
You need to store the original text and bring it back when the mouse leaves.
var element = getElementById('content'),
storedText;
function hover(description) {
console.log(description);
storedText = element.innerHTML;
element.innerHTML = description;
}
function leave() {
element.innerHTML = storedText;
}
<div id="content">
Stuff should be placed here.
</div>
<br/>
<br/>
<br/>
<ul>
<li onmouseover="hover('Apples are delicious')" onmouseleave="leave()">Apple</li>
<li onmouseover="hover('oranges are healthy')" onmouseleave="leave()">Orange</li>
<li onmouseover="hover('Candy is the best')" onmouseleave="leave()">Candy</li>
</ul>
It is generally recommended to add event listeners in the JS code and not in the HTML, but put that aside for now.
i dont think in your code there was anything to make the content to go back to the default but i have made the least changes in your code to make the content to go back to default and i have used onmouseout event for that.
<div id="content">
Stuff should be placed here.
</div>
<br/>
<br/>
<br/>
<ul>
<li onmouseover="hover('Apples are delicious')" onmouseout="hover('Stuff should be placed here.')">Apple</li>
<li onmouseover="hover('oranges are healthy')" onmouseout="hover('Stuff should be placed here.')">Orange</li>
<li onmouseover="hover('Candy is the best')" onmouseout="hover('Stuff should be placed here.')">Candy</li>
</ul>
<script>
function hover(description) {
console.log(description);
document.getElementById('content').innerHTML = description;
}
</script>
You can achieve the same without any Javascript:
li::before { content: attr(data-text); }
li:hover::before { content: attr(data-text-hover); }
<ul>
<li data-text-hover="Apples are delicious" data-text="Apple"></li>
<li data-text-hover="Oranges are healthy" data-text="Orange"></li>
<li data-text-hover="Candy is the best" data-text="Candy"></li>
</ul>

Simple HTML Javascript button onclick function not working

So essentially I want to keep this as simple as possible, meaning no jquery or bootstrap etc... just straight javascript, HTML and CSS. This is what I have so far
Javscript:
var menuOptions= document.getElementsByClassName("nav");
var hamburger= document.getElementById("nav-btn");
function myFunction() {
hamburger.onclick= menuOptions.style.visibility= 'visible';
}
HTML:
<HTML>
<button onclick="myFunction()">
<span id="nav-btn">
<image src="Menugreen.png" alt="collapsable menu"/>
</span>
</button>
<div class="nav">
<ul>
<li id="Programs"> Programs </li>
<li> T-Shirts </li>
<li id="About"> About </li>
</ul>
</div>
</HTML>
CSS:
.nav {
visibility: hidden;
}
Besides just giving me a solution I would highly appreciate it if you could explain why my current method does not work and why yours does. Thanks in advance!
Two problems:
getElementsByClassName() returns a list, not a single element (though the list may contain just a single element), and that list doesn't have a .style property. You can use menuOptions[0] to access the first (and in this case only) element in the list.
You don't want to say hamburger.onclick= inside your function, because that would be assigning a new onclick handler but your function is already being called from the onclick attribute of your button. (Also, if you were trying to assign a new click handler you'd want hamburger.onclick = function() { /* something */ }.)
So the minimum change to your existing code to get it to work would be to change this line:
hamburger.onclick= menuOptions.style.visibility= 'visible';
...to this:
menuOptions[0].style.visibility = 'visible';
In context:
var menuOptions= document.getElementsByClassName("nav");
var hamburger= document.getElementById("nav-btn");
function myFunction() {
menuOptions[0].style.visibility = 'visible';
}
.nav {
visibility: hidden;
}
<HTML>
<button onclick="myFunction()">
<span id="nav-btn">
<image src="Menugreen.png" alt="collapsable menu"/>
</span>
</button>
<div class="nav">
<ul>
<li id="Programs"> Programs </li>
<li> T-Shirts </li>
<li id="About"> About </li>
</ul>
</div>
</HTML>
If you want repeated clicks on the button to toggle the menu display on and off then you can test the current visibility:
menuOptions[0].style.visibility =
menuOptions[0].style.visibility === 'visible' ? '' : 'visible';
Expand the following to see that working:
var menuOptions= document.getElementsByClassName("nav");
var hamburger= document.getElementById("nav-btn");
function myFunction() {
menuOptions[0].style.visibility =
menuOptions[0].style.visibility === 'visible' ? '' : 'visible';
}
.nav {
visibility: hidden;
}
<HTML>
<button onclick="myFunction()">
<span id="nav-btn">
<image src="Menugreen.png" alt="collapsable menu"/>
</span>
</button>
<div class="nav">
<ul>
<li id="Programs"> Programs </li>
<li> T-Shirts </li>
<li id="About"> About </li>
</ul>
</div>
</HTML>
There are a few reasons why your current setup does not function:
Document#getElementsByClassName returns a collection, and you are treating the result like a DOM element. You need to access an index like [0] to get an actual element.
Your toggle button only works one way, because visibility is set to visible but never set back to none when clicked again.
In myFunction, hamburger.onclick should not be assigned to the expression you chose. I am not sure why you tried to assign another click handler, but in order to make that work you would have needed to set it to a function () { ... }.
Now for my advice:
Use CSS classes to control whether the menu is hidden or not, rather than messing around with the style property in your JS. You can use the classList property of DOM elements to .add(), .remove(), and .toggle() a specific class when myFunction is run. I have chosen to use toggle because I think that most suits your use case.
Use element.addEventListener instead of HTML attributes like onclick.
Snippet:
var menuOptions = document.getElementsByClassName("nav")[0]
var hamburger = document.getElementById("nav-btn")
hamburger.parentNode.addEventListener('click', function myFunction() {
menuOptions.classList.toggle('hidden')
})
.nav.hidden {
visibility: hidden;
}
<button>
<span id="nav-btn">
<img src="Menugreen.png" alt="collapsable menu"/>
</span>
</button>
<div class="nav hidden">
<ul>
<li id="Programs"> Programs </li>
<li> T-Shirts </li>
<li id="About"> About </li>
</ul>
</div>

Only show certain <div> if there's a certain element on the page

I'm trying to get the company I'm at a Help Centre set up, using Zendesk.
I've managed to implement a sidenav, but I'm struggling to make it show different anchor links depending on the category of the Help Centre the user is on. Zendesk only allows you to edit the HTML of the category page template, and I'm unable to dynamically load in the links.
Can anyone please advise on how to show DIV_1, only if the page contains <li title="Using ProductName">? I've searched but can't seem to find anything relevant.
From there I'll do the same for the other sections in the same way (e.g. only show DIV_2 if the page contains <li title="Developer Portal".
For reference, I have access to the category's HTML template, the CSS and JS.
Thanks in advance!
<div class="container">
<nav class="sub-nav">
<ol class="breadcrumbs">
<li title="Help Centre">
Help Centre
</li>
<li title="Using ProductName">
Using ProductName
</li>
</ol>
<div id="DIV_1">
<ul id="UL_2">
<li id="LI_1">
Admin and Settings
</li>
<li id="LI_1">
Getting Started
</li>
<li id="LI_1">
Content Types and Sources
</li>
<li id="LI_1">
Content Management
</li>
<li id="LI_1">
Content Publishing
</li>
<li id="LI_1">
Apps
</li>
<li id="LI_1">
Analytics
</li>
<li id="LI_1">
Troubleshooting
</li>
</ul>
</div>
</div>
</div>
You can use the built-in DOM query methods to accomplish this. In this case, you'd want to combine an if condition with the query, something like so:
if (document.querySelector('li[title="Using ProductName"]')) {
// make #DIV_1 visible however you please here
document.querySelector('#DIV_1').display = 'block';
}
If the li with the title Using ProductName does not exist, #DIV_1 will stay invisible; if it does, it will be shown.
You can do a quick for loop check:
var items = document.getElementsByTagName('li');
for (var i = 0; i < items.length; i++) {
if (items[i].title == titleToCheckFor) { showElement(); }
}
You can fill in titleToCheckFor with the title you're looking for ("Using _____") and the showElement function would display the div, or you could just show the div right in the loop.
Using DOM query method querySelector you can search the target element, by default we set all div's hidden, and then we show only the required.
<style>
.module {
display:none;
}
</style>
<script>
// by default we show MODULE A else show module B
var module = "DIV_1";
if (document.querySelector('li[title="Developer Portal"]')) {
module = "DIV_2";
}
// we show the respective DIV
document.querySelector('.' + module).display = 'block';
</script>
<div class="module DIV_1" id="DIV_1">
...
</div>
<div class="module DIV_2" id="DIV_2">
....
</div>
You can achieve this via CSS classes.
SOLUTION 1:
This being the sample HTML:
<div id="Div_1" class="menu-div using-productname">
</div>
<div id="Div_2" class="menu-div help-centre">
</div>
<div id="Div_3" class="menu-div other-tab">
</div>
Now you should setup your css like:
.menu-div {
display: none;
}
So all menu divs are hidden by default when the page loads
Now when you move to some tab suppose "Using ProductName", all you need to do is
var title = "Using ProductName"; //Get the title
var className = title.split(" ").join("-").toLowerCase(); //Convert it to the correct class which matches with your Divs in the menu
document.querySelector(".menu-div").style.display = "none"; //Set all menu divs to hidden
document.querySelector("." + className).style.display = "block"; //Show the desired menu div
SOLUTION 2:
This being the sample HTML:
<div class="parent-div">
<div id="Div_1" class="menu-div">
</div>
<div id="Div_2" class="menu-div">
</div>
<div id="Div_3" class="menu-div">
</div>
Now you should setup your css like:
.parent-div .menu-div {
display: none;
}
.parent-div.using-productname #Div_1 {
display: block;
}
.parent-div.help-centre #Div_2 {
display: block;
}
.parent-div.other-tab #Div_3 {
display: block;
}
Now when you move to some tab suppose "Using ProductName", all you need to do is
var title = "Using ProductName"; //Get the title
var className = title.split(" ").join("-").toLowerCase(); //Convert it to the correct class which you will add to the parent
document.querySelector(".parent-div").className = "parent-div " + className; //Set the parent div class to the className - the css will take care of the rest!
NOTE - Also you should use different ids on your different LIs and A tags.
You can use jQuery in Zendesk Help Centers so
var test = $('.breadcrumbs').children(':contains(amy)')
if(test.length > 0) {
do something here like
$('#LI_1').hide();
}
It's kind of simple brute force, but it works.

Change max height element after it being clicked

I'm writting a dropdown menu and I wanted to have the dropdown being controlled by javascript.
My dropdown has the sub menu hidden of sight max-height: 0px; and when the correspondent anchor tag is clicked, I change its max-height parameter to 400px, using the following function:
function drop_down(name) {
document.getElementById(name).style.maxHeight = "400px";
}
So far so good. The problem is that the element's max-height, stays at 400px and the sub menu does not hide. So I thought that I should target the click of the mouse and when this happens check if there is any element with 400px and change it back to 0.
$('html').click(function() {
var max_h = document.getElementsByClassName("nav_content");
var i;
for(i = 0 ; i < max_h.length ; i++)
{
if(max_h[i].style.maxHeight == "400px")
{
max_h[i].style.maxHeight = "0px";
}
}
});
What happens is that this function tracks every click, even the one used to display the sub menu. So my question is: is there a way to only activate the second function after I clicked my sub-menu? Because I always want the click that comes after the menu is displayed to close the sub menu.
HTML:
<body>
<div class="nav_container">
<nav class="nav_main">
<div class="logo">
<a href="#">
<img src="../majo.png" alt="logo">
</a>
</div>
<ul class="nav" id="nav">
<li>
Home
</li>
<li>
Consultas
<div id="nav_consul" class="nav_content">
<div class="nav_sub">
<ul>
<li>
Informação Dia a Dia
</li>
<li>
Totais Mensais
</li>
<li>
Tarifário Atual da Rede
</li>
<li>
Data específica
</li>
<li>
Atividade do Sistema
</li>
<li>
Coimas
</li>
</ul>
</div>
</div>
</li>
<li>
Simulações
<div id="nav_simul" class="nav_content">
<div class="nav_sub">
<ul>
<li>
Criar tarifa Simples
</li>
<li>
Criar tarifa Complexa
</li>
<li>
Simular com Nova Tarifa
</li>
</ul>
</div>
</div>
</li>
<li>
Preferências
<div id="nav_prefs" class="nav_content">
<div class="nav_sub">
<ul>
<li>
Lista de acessos
</li>
<li>
Alterar Password
</li>
<li>
Alterar Dados de Conta
</li>
</ul>
</div>
</div>
</li>
<li>
Log Out
</li>
</ul>
</nav>
</div>
<div id="content_main">
</div>
<footer></footer>
<script src="../js/jQuery.js"></script>
<script src="../js/user_menu.js"></script>
<script src="../js/user_nav.js"></script>
<script src="../js/user_clear_sub_menu.js"></script>
</body>
Here is an easy solution:
Create the following CSS-Styles:
.nav_content.visible {
max-height: 400px;
}
.nav_content.invisible {
max-height: 0px;
}
Set the overflow property for your nav_content to hidden:
.nav_content{
overflow: hidden;
}
Now add the class invisible to your submenus, if you want them to be invisible by default (you can do this manually in the markup or by js code):
Manually e.g.:
<div id="nav_prefs" class="nav_content invisible">
or by code (after the elements have been loaded):
$(".nav_content").addClass("invisible);
Now, if you just need to adjust your drop_down function to toggle the element's invisible/visible class:
function drop_down(dropdownID){
$('#'+dropdownID).toggleClass("visible invisible");
}
UPDATE: To make all visible submenus disappear when clicked elsewhere use this piece of code, when the window is loaded:
$(document).on('click', function (e) {
if (!$(e.target).is('.nav_item') && !$(".nav_item").has(e.target).length !== 0) {
$('.nav_content.visible').toggleClass("visible invisible");
}
});
If you only want to have one submenu visible at a time, you can use this version of your drop_down function:
function drop_down(dropdownID) {
$('.nav_content.visible').toggleClass("visible invisible");
$('#' + dropdownID).toggleClass("visible invisible");
}
A working fiddle can be found here
EDIT: Since you used jQuery in your original code, I assumed the answer can use jQuery too
You'll want to create a click handler on your document, then check the target of the click. If the target of the click has a certain class, use the menu behavior. If not, or if it's a sub-menu, close the menu.
Here's a question with multiple examples:
How do I close menu on click and when the user clicks away?
Also, I'd recommend not using max-height to hide and show. Since you're using jquery already, you could just use hide() and show().
One more thing: since you're using jquery already, you don't need to use these calls: document.getElementById(name). You can do a $("#yourId") or for document.getElementsByClassName("nav_content"); you can use $(".your-class")
It looks like you attached click event to entire document. I think you need to change only $('html').click(function() { to something like $('sub-menu-selector').click(function() { to
only activate the second function after I clicked my sub-menu
Aside to that, since it's only piece of jQuery and if you're not using it elsewhere, I would replace this with addEventListener and attachEvent, but maybe that's just me :)
In that case you can use jQuery.not() method to exclude the dropdown menu from your jQuery selection, here's what you need :
$('html').not(document.getElementsByClassName("nav_container")[0]).click(function() {
//As you can pass an element to it
You can also use the :not in your first selector like this:
$('html:not(div.nav_container))

How can I highlight a selected list item with jquery?

I have several items in a list and want to highlight the one a user clicks on by applying some css style, maybe a background color etc.
My HTML looks like this:
<ul class="thumbnails">
<li>
<a href="#" class="thumbnail">
<img class="giftthumb" src='thumb1.jpg' alt="">
<span class="gifttitle">Thumb1</span>
</a>
</li>
<li>
<a href="#" class="thumbnail">
<img class="giftthumb" src='thumb2.jpg' alt="">
<span class="gifttitle">Thumb3</span>
</a>
</li>
<li>
<a href="#" class="thumbnail">
<img class="giftthumb" src='thumb3.jpg' alt="">
<span class="gifttitle">Thumb3</span>
</a>
</li>
</ul>
jQUery to retrieve selected item:
$('.thumbnail').click(function(e) {
e.preventDefault();
???
})
You could use jQuery's class management methods (namely addClass() and removeClass() in this case) to add a class on the selected item and remove the same class from all the other items (if you want only one selected at a time).
//save class name so it can be reused easily
//if I want to change it, I have to change it one place
var classHighlight = 'highlight';
//.click() will return the result of $('.thumbnail')
//I save it for future reference so I don't have to query the DOM again
var $thumbs = $('.thumbnail').click(function(e) {
e.preventDefault();
//run removeClass on every element
//if the elements are not static, you might want to rerun $('.thumbnail')
//instead of the saved $thumbs
$thumbs.removeClass(classHighlight);
//add the class to the currently clicked element (this)
$(this).addClass(classHighlight);
});
Then in your CSS just add:
.highlight {
background-color: cyan;
font-weight: bold;
}
jsFiddle Demo
This is a better solution than changing CSS properties directly from jQuery/Javascript (with the .css() method for example), because separation of concerns will make your code more manageable and readable.
$('.thumbnail').click(function(e) {
e.preventDefault();
$(this).css('background-color', 'red');
})
Your ??? would be:
$('.thumbnail').removeClass('selected');
$(this).addClass('selected');
Then all you have to do is define your 'selected' css class.
If you don't need the active to be persistent here's a CSS way:
li:focus{
background: red;
}
li:active{
background: gold;
}
<ul>
<li tabindex="1">Item 1</li>
<li tabindex="1">Item 2</li>
<li tabindex="1">Item 3</li>
</ul>
Now click <b>here</b> and see why it's not persistent.
in some situations the above might be useful - to only highlight the currently "click-active" item…

Categories