I'm in the process of learning Javascript and I'm trying to create a simple dropdown menu.
An example of my desired functionality can be seen on the google homepage in the top menu with the "more" and "settings" dropdown.
I have a ul that is set to display:inline using the onclick() JS event handler. How do I make the ul go back to display:none when I click any where else on the page other than the now visible ul?
I've Googled about blur and setting the focus to another element but I don't know how to actually do it.
I want to do this in straight Javascript, not jQuery.
Here is the html I use:
<div class="info">
Some Text Boom A <a onclick="menu('id1');">Link</a> | More text
<a onclick="menu('id2');">Another Link</a> | more text
<ul id="id1" class="submenu">
<li>A1</li>
<li>A2 This is Long</li>
<li>A3</li>
</ul>
<ul id="id2" class="submenu">
<li>B1</li>
<li>B2</li>
<li>B3</li>
</ul>
</div>
When the user clicks on one of the linked <a> tags, the <ul> which is hidden and directly below the <a> tag becomes visible. I want the <ul> element to dissapear when the user clicks anywhere but the <ul>.
Edit:
Here is my javascript:
function menu(id) {
var myLayer = document.getElementById(id);
if (myLayer.style.display == "none" || myLayer.style.display == "") {
myLayer.style.display = "block";
} else {
myLayer.style.display = "none";
}
}
Edit 2:
Complete CodE:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>Untitled 1</title>
<style type="text/css">
a
{
color:blue;
}
.info ul.submenu
{
border: solid 1px #e0e0e0;
background-color: #fff;
position: absolute;
padding: 0;
z-index: 2;
display: none;
}
.info ul.submenu li
{
display: block;
border-top: solid 1px #e0e0e0;
margin: 0px 10px 0 10px;
}
.info ul.submenu li a
{
display: block;
padding: 7px 0px 6px 0;
color: #1177ee;
cursor:pointer;
}
</style>
<script type="text/javascript">
function menu(id) {
var myLayer = document.getElementById(id);
myLayer.onblur = function() {
myLayer.style.display = 'none';
};
if (myLayer.style.display == "none" || myLayer.style.display == "") {
myLayer.style.display = "block";
} else {
myLayer.style.display = "none";
}
}
</script>
</head>
<body>
<div class="info">
Some Text Boom A <a onclick="menu('id1');">Link</a> | More text
<a onclick="menu('id2');">Another Link</a> | more text
<ul id="id1" class="submenu">
<li>A1</li>
<li>A2 This is Long</li>
<li>A3</li>
</ul>
<ul id="id2" class="submenu">
<li>B1</li>
<li>B2</li>
<li>B3</li>
</ul>
</div>
</body>
</html>
This is quite simple actually.
Once you have a reference to the DOM element that you want to bind the blur event listener to, assign it like this:
myLayer.onblur = function() {
myLayer.style.display = 'none';
};
jQuery creates a blur event you can bind a function to, is there a strong reason not to use jQuery? Using a JavaScript library even if it is just for event handling, helps insulate you from browser differences. I've only ever used focus/blur events for text input or textarea elements in a form. It sounds like you want a list to float on top of the other elements. I'd position the list relatively and give it a z-index that is higher than the background. I'd bind a click event to the area outside the list, to dismiss the list pop-up. Is toggling a pop-up/modal window what you want? I'd have a look at jQuery SimpleModal for modal window examples, or look at how one is implemented if you want to roll your own.
If you are looking for a way to stop "onclick" event if it happens inside your menu then "event.stopPropagation();" may be what you need
<body onclick="menu('id1'); menu('id2');">
<div class="info">
Some Text Boom A <a onclick="menu('id1');">Link</a> | More text
<a onclick="menu('id2');">Another Link</a> | more text
<ul id="id1" class="submenu" onclick="alert('click menu'); event.stopPropagation();">
<li>A1</li>
<li>A2 This is Long</li>
<li>A3</li>
</ul>
<ul id="id2" class="submenu" onclick="alert('click menu'); event.stopPropagation();">
<li>B1</li>
<li>B2</li>
<li>B3</li>
</ul>
</div>
</body>
Related
I am attending an entry level HTML/CSS/JS course and our first assignment is to make a simple website about ourselves. We need to have a horizontal menu that when clicked displays certain information. For example, clicking "description" should display a short paragraph describing ourselves. From what I've researched it seems that my answer lies with using JQuery but I don't believe he expects us to know that nor utilize it this early. Is there another option that I may not be seeing?
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="style.css">
<title>Jeremy Ortiz</title>
<div id="header">
<h1>A Little About Jeremy Ortiz</h1>
</div>
</head>
<body>
<img src="hwpic.jpg" alt="Me">
<div id="content">
<div id="nav">
<h2>Navigation</h2>
<ul>
<li><a class="selected" href="">Description</a></li>
<li>A form</li>
<li>Course List</li>
<li>Table</li>
<li>Contact Information</li>
</ul>
</div>
</body>
</html>
#header {
padding: 10px;
background-color: #6CF;
color: white;
text-align: center;
}
img {
position: absolute;
right: 7px;
bottom: 148px;
z-index: -1;
}
#content {
padding: 10px;
}
#nav {
width: 180px;
float: left;
}
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
My answer will assume your goal is to accomplish this task using basic Javascript instead of changing pages by navigating the user using the <a> elements. I understand that there are more efficient methods of performing this but I chose to present the information in a hopefully simple easily readable manner.
The way I would accomplish this is by changing your <a> elements:
<a class="selected" href="">Description</a>
To button elements and add the 'onclick' property with the function to call when the button is clicked:
<button onclick="displayDescription()">Click Me</button>
Now we need to create the elements that will be displayed upon clicking the button. For this we create some <div> other container that we can hide until the corresponding button is clicked.
<div id="description" style="display: none;">
Displayed when the description button is clicked.
</div>
Note** For every button we will need to create a <div style="display: none;"> to hide the information until its corresponding button is clicked.
Now we can create our Javascript function:
function displayDescription() {
var x = document.getElementById('description');
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
Note once again that in this method each Javascript function will map to a button in the same way each hidden will map to the same button.
If you need more help I recommend checking out w3schools and specifically for this problem here is a link to what you need to accomplish with your assignment.
http://www.w3schools.com/howto/howto_js_toggle_hide_show.asp
I hope this was helpful as I just wrote this during one of my college classes I will probably formalize my answer more at a later time today.
please help me for remove or hide my #id on url browser.
example:
my menu1 target on "#p1"
my site "mysite.com/index.htm"
when i click menu1 on my browser will like this "mysite.com/index.htm#p1"
i need my id not show on url browser just "mysite.com/index.htm" not like this "mysite.com/index.htm#p1"
#p1:target { background: red;}
#p2:target{ background: green;}
#p3:target{ background: blue;}
#p4:target{ background: yellow;}
#p5:target{ background: coral;}
#p6:target{ background: skyblue;}
ul{list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #333;
}
li {float: left;}
li a{ display: inline-block;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;}
li a:hover {
background-color: #111;
}
<div id="menu">
<input type="checkbox" id="tbl-menu"/>
<label for="tbl-menu"><img src="drop.png" height="40px" width="40px" alt=""></label>
<nav class="nav">
<ul class="tombol">
<li class="tombolmenu">
<a class="t1" href="#p1">Menu1</a></li>
<li><a class="t2" href="#p2">Menu2</a></li>
<li><a class="t3" href="#p3">Menu3</a></li>
<li><a class="t4" href="#p4">Menu4</a></li>
<li><a class="t5" href="#p5">Menu5</a></li>
<li><a class="t6" href="#p6">Menu6</a></li>
</ul>
</nav>
</div>
<!-- My page target -->
<div id="p1"> Page1 </div>
<div id="p2"> Page2 </div>
<div id="p3"> Page3 </div>
<div id="p4"> Page4 </div>
<div id="p5"> Page5 </div>
<div id="p6"> Page6 </div>
I know this question is starting to be old in Internet years but I thought I'd share my solution (which is loosely based off Janmejay Agrawal's).
It basically replaces the standard behaviour of a hyperlink and creates a smooth scrolling to the desired element.
This code uses "vanilla" JS and should work with most web browsers.
//Get all the hyperlink elements
var links = document.getElementsByTagName("a");
//Browse the previously created array
Array.prototype.forEach.call(links, function(elem, index) {
//Get the hyperlink target and if it refers to an id go inside condition
var elemAttr = elem.getAttribute("href");
if(elemAttr && elemAttr.includes("#")) {
//Replace the regular action with a scrolling to target on click
elem.addEventListener("click", function(ev) {
ev.preventDefault();
//Scroll to the target element using replace() and regex to find the href's target id
document.getElementById(elemAttr.replace(/#/g, "")).scrollIntoView({
behavior: "smooth",
block: "start",
inline: "nearest"
});
});
}
});
Should this code not be correct, please feel free to point it out !
There are several ways to do it, and my favourite is to make a custom function to scroll to in page link instead of relying on browser for it.
Like this
$("a[href^='#']").click(function(e){
e.preventDefault();
var elem = $($(this).attr('href'));
/* check for broken link */
if(elem.length)
$(window).animate('scrollTop' , elem.offset().top)
})
In addition of hiding '#id' from url it'll also animate scrolling.
Hope It'll help.
So i have multiple buttons that is showing when it's clicked.
But i'm having a hard time hiding the content if another button is clicked.
The Javascript code looks like this
function portFunction() {
var e = document.getElementById("test2").style;
if(!e.display | e.display == "none"){
e.display = "block";
}
else{
e.display = "none";
}
}
And the html
<nav>
<ul>
<li onclick="portFunction();">Portfolio</li>
<li onclick="blogFunction();">Blog</li>
</ul>
</nav>
How can i make it so if another button is clicked, it hides the content for the last button that was open and display the new button content?
EDIT
Snippet code, ok so if you click on Portfolio some text will be displayed. But if you click on Blog some other text will be displayed, but the text from Portfolio will still be displayed. What i want is, if you click the Portfolio button and then the Blog button, the text from portfolio should go away. And i want this for every button.
function blogFunction() {
var e = document.getElementById("test").style;
if(!e.display | e.display == "none"){
e.display = "block";
}
else{
e.display = "none";
}
}
function portFunction() {
var e = document.getElementById("test2").style;
if(!e.display | e.display == "none"){
e.display = "block";
}
else{
e.display = "none";
}
}
#import url(http://fonts.googleapis.com/css?family=Open+Sans);
.center{
font: 100% open sans, sans-serif;
margin:0;
padding:0;
}
#test{
display:none;
height:20%;
width:20%;
z-index:11;
position:absolute;
left:50%;
right: 50%;
}
.testText{
color:red;
z-index:11;
}
#test2{
display:none;
height:20%;
width:20%;
z-index:11;
position:absolute;
left:50%;
}
<nav>
<ul>
<li class="current">Home</li>
<li onclick="portFunction();">Portfolio</li>
<li onclick="blogFunction();">Blog</li>
<li>About</li>
<li>Contact</li>
<li>Preview</li>
</ul>
</nav>
<div class="center">
<div id="test">
<h1 class="testText">
Test
</h1>
</div>
<div id="test2">
<h1 class="testText">
Test2
</h1>
</div>
</div>
A simpler way to do this would be to use classes and jQuery's eq() something like this:
$('.section-link').click(function() {
var cur = $('.section-link').index($(this)); // get the index of the clicked link
$('.section-display').removeClass('active'); // hide all of the sections
$('.section-display').eq(cur).addClass('active'); // show the section at the same index of the clicked link
});
.section-display:not(.active) {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav>
<ul>
<li class="section-link">Portfolio
</li>
<li class="section-link">Blog
</li>
</ul>
</nav>
<br>
<br>
<div class="section-display active">Section One</div>
<div class="section-display">Section Two</div>
In response to your comment, Let's take the code line by line:
First, the CSS rule .section-display:not(.active) { display: none; } hides every element that has the class section-display, unless it also has the class active. This makes all of the divs hidden but allows you to add the classactive if you want a particular section to be shown by default.
In the jQuery, $('.section-link').click(function() { }); is a click handler. Basically, it says when someone clicks on an element that has the class section-link, run the code in this block
Inside the handler, the variable $(this) refers to a jQuery object that represents the element that was clicked (in your case a link).
The first line, var cur = $('.section-link').index($(this)); says, gather all of the elements that have the class section-link (all of you links) into an array and give me the index of the one that was clicked. So now we know that the user clicked the 2nd link for example.
The next line $('.section-display').removeClass('active'); removes the class active from all of the divs that have the class section-display which hides all the divs because of the css rule
On the next line $('.section-display').eq(cur).addClass('active');, $('.section-display') gathers all of the divs that have the class section-display into an array (these are the divs with the content). After that .eq(cur) selects the div from the array that is at the same index as the link that was clicked. And finally .addClass('active') adds the class active to the element which displays the4 element because of the css rule.
So now, clicking on the first section-link element will show the first section-display div and hide all others. Clicking on the second section-link element will show the second section-display div and hide all others. And so on...
I added a callLastFunc() function, it saves and calls previous function, to hide the content added by previous function call.
var lastCalled = null;
function callLastFunc(arg) {
if (arg[0])
return;
if (lastCalled)
lastCalled("byCallPrev");
lastCalled = arg.callee;
}
function blogFunction() {
var e = document.getElementById("test").style;
if(!e.display | e.display == "none"){
e.display = "block";
}
else{
e.display = "none";
}
callLastFunc(arguments);
}
function portFunction() {
var e = document.getElementById("test2").style;
if(!e.display | e.display == "none"){
e.display = "block";
}
else{
e.display = "none";
}
callLastFunc(arguments);
}
#import url(http://fonts.googleapis.com/css?family=Open+Sans);
.center{
font: 100% open sans, sans-serif;
margin:0;
padding:0;
}
#test{
display:none;
height:20%;
width:20%;
z-index:11;
position:absolute;
left:50%;
right: 50%;
}
.testText{
color:red;
z-index:11;
}
#test2{
display:none;
height:20%;
width:20%;
z-index:11;
position:absolute;
left:50%;
}
<nav>
<ul>
<li class="current">Home</li>
<li onclick="portFunction();">Portfolio</li>
<li onclick="blogFunction();">Blog</li>
<li>About</li>
<li>Contact</li>
<li>Preview</li>
</ul>
</nav>
<div class="center">
<div id="test">
<h1 class="testText">
Test
</h1>
</div>
<div id="test2">
<h1 class="testText">
Test2
</h1>
</div>
</div>
Hmm, you would be better to use a framework, but this is what you want right?
This example make use of vanillaJS Framework, which is very powerful out of the box ;)
// lib.js
sitesContent = {};
// blog.js
sitesContent['blog'] = "Blog content"; // You can use templates like handlebars
// portfolio.js
sitesContent['portfolio'] = "Portfolio content"; // Better to use templates
// app.js
function navAction(site) {
document.getElementById('content').innerHTML = sitesContent[site];
}
navAction('portfolio'); // Means load portfolio when loaded first time
<nav>
<ul>
<li><a onclick="navAction('portfolio')" href="#">Portfolio</a></li>
<li><a onclick="navAction('blog')" href="#">Blog</a></li>
</ul>
</nav>
<div id="content"></div>
So when someone hover a <li> I need that my Div get his class changed.
How can I do This?
Is this possibile using only css or do I need to put some JS inside?
Edit 1: each li will have a especific id, and the div would recive the id as a class.
I think you should to use JQuery:
$(document).ready(function(){
$("li").mouseover(function(event){
$("#capa").addClass("class");
});
});
To assign a class to the parenting <div> element based on the ID of a hovered child <li>, first check for the hover and get the ID name, then assign it to the parenting <div>.
The following is a code that you will be able to use for several divs on a page, and it will reset the class names on leaving the <li> hover, by using the out handler of the jQuery method:
$(".changeme ul li").hover(function(){
$(this).parents("div").addClass($(this).attr("id"));
}, function(){
$(this).parents("div").removeClass($(this).attr("id"));
});
.changeme{
background-color:#eee;
}
.changeme.firstli{
background-color:#ffd;
}
.changeme.secondli{
background-color:#fdd;
}
.changeme.thirdli{
background-color:#dfd;
}
.changeme.fourthli{
background-color:#ddf;
}
.changeme.fifthli{
background-color:#ddd;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="unaffected">
<p> some other parenting div, not affected</p>
<div class="changeme">
<p>some text, nothing changes</p>
<ul>
<li id="firstli">we are changing our parentting div!</li>
<li id="secondli">we are changing our parentting div!</li>
<li id="thirdli">we are changing our parentting div!</li>
</ul>
<p>some text, nothing changes</p>
<ul>
<li id="fourthli">we are changing our parentting div!</li>
<li id="fifthli">we are changing our parentting div!</li>
</ul>
<p>some text, nothing changes</p>
</div>
</div>
https://jsfiddle.net/svArtist/adq5dr68/
Go to your div style class definitions and add "li:hover" near the name;
.yourDiv { font-size:14pt; }
then turn to this
.yourDiv li:hover { font-size:14pt; }
You could just use the :hover property, that way you wouldn't have to change the div's class, which you can only do with javascript.
CSS hover attributes can be used to specify how an element should appear on hover, but not how some other element should appear when the first is hovered over. Achieving behavior of that complexity requires a touch of JavaScript.
(function() {
var div = document.getElementById("parent"); // save a reference to the target div
var lis = div.querySelectorAll("li"); // get your <li> tags
for (var i = 0, len = lis.length; i < len; i++) {
lis[i].onmouseover = updateDivClass; // attach the event listener to each tag
}
div.onmouseout = function() { // remove class when no longer hovering over div
this.className = "";
};
function updateDivClass() { // apply class to div when hovering over <li> tag
div.className = this.id;
}
})();
.Class1 {
background-color: #df7000;
font-family: Calibri;
color: black;
}
.Class2 {
background-color: purple;
color: white;
font-family: Segoe UI;
}
.Class3 {
background-color: black;
color: lightgreen;
font-family: courier;
}
<div id="parent">
Hover over a class below to apply the class to the entire div.
<ul>
<li id="Class1">Black Calibri with Orange Background</li>
<li id="Class2">White Segoe UI with Purple Background</li>
<li id="Class3">Light Green Courier with Black Background</li>
</ul>
</div>
Alright so I have a nested sortable list, each item is therefore both a container and a sortable element.
The problem I am facing is that, whenever I add a new element, I want jQuery to refresh its internal state with the new item.
According to the documentation, one has to call the sortable method passing as parameter 'refresh', but still I can't make it work.
Sample code:
http://jsfiddle.net/X5sBm/
JavaScript:
$(document).ready(function() {
var list = $('#mycontainer ul').sortable({
connectWith: '#mycontainer ul',
placeholder: 'myplaceholder'
});
function addElement(text) {
$('#mycontainer > ul').append('<li>' + text + '<ul></ul></li>');
list.sortable('refresh');
}
addElement('yolo');
});
HTML:
<div id="mycontainer">
<ul>
<li>
Some text
<ul>
</ul>
</li>
<li>
Some text 2
<ul>
</ul>
</li>
</ul>
</div>
CSS:
#mycontainer > ul {
display: block;
}
#mycontainer > ul ul {
min-height: 10px;
padding-left: 20px;
}
.myplaceholder {
background-color: yellow;
}
Try to drag one pre existing item under the newly added one, you won't be able to do so even after the refresh.
I found a cheap fix:
I call sortable again on the same tag reinitialising the Sortable plugin like so:
$('#mycontainer ul').sortable({
connectWith: '#mycontainer ul',
placeholder: 'myplaceholder'
});
and it works.
The key understanding and take-away is to make the dynamically created <ul></ul> initialized with the sortable options. I suggest making an options object for easy re-use.
$(document).ready(function() {
const container = $('#mycontainer ul');
const options = {
connectWith: '#mycontainer ul',
placeholder: 'myplaceholder'
};
container.sortable(options);
function addElement(text) {
let newListItem = $('<li>').text(text);
newListItem.append($('<ul>').sortable(options)); // <- key concept
$('#mycontainer > ul').append(newListItem);
//container.sortable('refresh');
}
addElement('yolo');
});
#mycontainer > ul {
display: block;
}
#mycontainer ul ul {
min-height: 10px;
padding-left: 20px;
}
.myplaceholder {
background-color: yellow;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="mycontainer">
<ul>
<li>
Some text
<ul>
</ul>
</li>
<li>
Some text 2
<ul>
</ul>
</li>
<li>
Some text 3
<ul>
</ul>
</li>
</ul>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
</body>
</html>