My javascript mobile menu only opens when double clicked. - javascript

I'm making a website for my friend using just HTML/CSS3 and Vanilla JS. Everything seems to be going OK but I can't figure out why my mobile menu only opens when I click it twice. It only does this the first time I try clicking it after refreshing the page. Once it's open I can open and close it again with one click.
Here is the relevant HTML
<header id = "top-menu">
<img id = "title-image" class = "desktop-site" src = "images/ben-the-mover-guy.png">
<img id = "mobile-title-image" class = "mobile-site" src = "images/mobile-title-white.png">
<h1 id = "title-text">Ben the Mover Guy</h1>
<a id = "mobile-icon" href = "javascript:void(0);" onClick = "dropDown()"><i id = "mobile-icon-id" class = "ion-navicon-round"></i></a>
<nav id = "icon-nav" class = "desktop-site">
<i class = "ion-social-facebook"></i>
<i class = "ion-android-mail"></i>
<i class = "ion-ios-calculator"></i>
</nav>
<nav id = "main-nav" class = "horizontal-nav desktop-site">
<span class = "selected">ABOUT</span>
RATES
<span class = "link-break-line">PREPARING FOR</span> YOUR MOVE
CONTACT
</nav>
</header>
and Javascript
function dropDown() {
var x = document.getElementById("main-nav");
var y = document.getElementById("mobile-icon-id");
if (x.className === "horizontal-nav") {
x.className = "mobile-nav";
y.className = "ion-close-round"
} else {
x.className = "horizontal-nav";
y.className = "ion-navicon-round"
}
}
The issue is definitely not the CSS. After hitting up Inspect Element I noticed that it's not changing the class name to "mobile-nav" until the second click, so it's an issue with the JS.
I did a mock website a while ago where I used similar code and I didn't have this problem. The only difference was that I used a div with a unordered list for the nav links instead of the '' tag. That wouldn't have anything to do with it would it?

The reason this is occurring is because you're checking the className attribute, which contains all classes of the element. The first time it's being checked, the value is not horizontal-nav -- it's horizontal-nav desktop-site, which causes the code in the else block to fire. The second time around, it is horizontal-nav, so it works correctly.
Use x.classList.contains("horizontal-nav"), or build/use a method to check whether className contains horizontal-nav rather than is horizontal-nav. jQuery's hasClass works perfectly for this, if you need to support older browsers.

change your js function to this and it will work..
function dropDown() {
var x = document.getElementById("main-nav");
var y = document.getElementById("mobile-icon-id");
if (x.classList.contains("horizontal-nav")) {
x.className = "mobile-nav";
y.className = "ion-close-round"
} else {
x.className = "horizontal-nav";
y.className = "ion-navicon-round"
}
}

Related

How can i target appended items one by one in javascript?

I created a simple new tab page similar to web browsers, but when I create a new tab and press the x icon to triger closetab() it closes all the tabs and does not delete them in order one by one. How do i make each of appended items unique?
JS:
function addTab() {
var img = document.createElement("img");
img.src = "resources/img/delete-icon.svg";
img.className = 'deleteicon';
img.id = "deletetab";
img.onclick = closeTab;
var ulLocation = document.getElementsByClassName('abc')[0];
var whereTab = document.getElementById('listid');
var addTab = document.createElement('li');
addTab.className = 'first-tab';
addTab.id = "listid";
addTab.className = 'active';
addTab.innerHTML = "mozilla-firefox/newtab";
addTab.appendChild(img2);
ulLocation.appendChild(addTab);
addTab.appendChild(img);
}
function closeTab() {
var whereTab = document.getElementById('listid');
if (whereTab.style.display == 'block') {
whereTab.style.display = 'none';
} else {
whereTab.style.display = "none";
}
}
You have at least 2 options. One is to target the active tab and close it when the X is clicked. This is assuming you only have one active tab at a time (denoted by an active class for example).
function closeTab(event) {
document.querySelector('li.tab.active').remove();
}
Another option is to reference the tab relative to the close icon, which you can reference in the event argument of your click listener. Since you're adding these dynamically, you can just remove them with the delete click rather than hide. Something like:
function closeTab(event) {
event.target.closest('li.tab').remove();
}
In these examples, you have set a className for your tab containers to be tab

javascript span click event - using google icon

I want to do an event where the "span" tag is btn and the "main" tag disappears, but it doesn't work at all. Is using the Google icon a problem?
GenreBtn is an icon using Google icon.
let genreBtn = document.querySelector(".genreClick")
let mainBox = document.getElementsByTagName("main")
genreBtn.addEventListener("click", function() {
mainBox.style.display = "none";
})
Use document.querySelector(".main")
Html-
<span class="genreClick" type="button"> Btn </span>
<div class="main"> Hide this </div>
Javascript -
let genreBtn = document.querySelector(".genreClick")
let mainBox = document.querySelector(".main")
genreBtn.addEventListener("click", function() {
mainBox.style.display = "none";
})
In your code, mainBox is HTML collection, not HTML element.
You can try like this:
let mainBox = document.querySelector('main')
Or
let mainBox = document.getElementsByTagName('main')[0]
// main tag must be exist, if there isn't main tage, [ mainBox.style.display = "none" ] will return error.

Why won't my JavaScript work!? It's selecting the ID but won't apply display changes

Before I get in to this, I know I should learn jQuery but I haven't got to that yet, I want to learn raw JavaScript first! Well, mostly. Can someone help me without the use of jQuery please just for understanding, thank you!:
Hi, I'm new to JavaScript, not long started learning it as you can see by the first code (which works so I'm leaving it) for the navigation.
However, my problem comes on the 2nd piece of code I'm trying something from a different angle after watching videos on event listeners etc and everything I have written makes sense, to me, I'm going through it step by step, it's selecting all the right stuff, but it's still not showing the desired result!!
When you click CSS i want it to show the div with id "cs", and same for the HTML and JavaScript ones.
I really don't know JavaScript enough to solve this myself, I can not think of anything AT ALL to help with the problem!
Somebody save me, please, my mind is going crazy and I want to go to bed!
Here is the code, and here is the JS fiddle: https://jsfiddle.net/pmj26o9p/2/
var htm = document.getElementById('htm');
var css = document.getElementById('css');
var js = document.getElementById('js');
htm.addEventListener("click", contentShow);
css.addEventListener("click", contentShow);
js.addEventListener("click", contentShow);
function contentShow() {
var whichOne = this.attributes["data-id"].value;
var switcheroo = document.getElementById(whichOne);
switcheroo.onclick = function() {
if (switcheroo.style.display === "none") {
switcheroo.style.display = "";
} else {
switcheroo.style.display = "none";
}
}
EDIT: On reading through the code again I don't think it will achieve what I want even if it works. This will let me show and hide whichever I'm clicking right?
I want to show the clicked one but then hide / apply display:none to all others that aren't clicked.
My example below will show the chosen block and hide the others, as per your EDIT comment.
var htm = document.getElementById('htm');
var css = document.getElementById('css');
var js = document.getElementById('js');
function contentShow(el) {
var whichOne = el.attributes["data-id"].value;
var switcheroo = document.getElementById(whichOne);
// show selected block, hide the others
switch (switcheroo) {
case htm:
htm.style.display = "block";
css.style.display = "none";
js.style.display = "none";
break;
case js:
htm.style.display = "none";
css.style.display = "none";
js.style.display = "block";
break;
case css:
htm.style.display = "none";
css.style.display = "block";
js.style.display = "none";
break;
}
}
<span data-id="htm" onClick="contentShow(this)" style="margin-right:10px;color:red; cursor:pointer">Click to show the HTML Block</span>
<span data-id="css" onClick="contentShow(this)" style="margin-right:10px;color:green; cursor:pointer">Click to show the CSS Block</span>
<span data-id="js" onClick="contentShow(this)" style="margin-right:10px;color:blue; cursor:pointer">Click to show the JS Block</span>
<br/>
<br/>
<div id="htm">Some HTML info here</div>
<div id="css" style="display:none">Some CSS info here</div>
<div id="js" style="display:none">Some JavaScript info here</div>
you are binding a second event handler to the switcheroo element, but the click event is not triggered so nothing happens.
If you want to make a toggle function on the switcheroo variable, you should do this instead:
function contentShow() {
var whichOne = this.attributes["data-id"].value;
var switcheroo = document.getElementById(whichOne);
return toggleDisplay(switcheroo);
}
function toggleDisplay(elem) {
if (elem.style.display === "none") {
elem.style.display = "";
} else {
elem.style.display = "none";
}
}
Ignoring your other bad practices, change
var htm = document.getElementById('htm');
var css = document.getElementById('css');
var js = document.getElementById('js');
htm.addEventListener("click", contentShow);
css.addEventListener("click", contentShow);
js.addEventListener("click", contentShow);
function contentShow() {
var whichOne = this.attributes["data-id"].value;
var switcheroo = document.getElementById(whichOne);
switcheroo.onclick = function() {
if (switcheroo.style.display === "none") {
switcheroo.style.display = "";
} else {
switcheroo.style.display = "none";
}
}
to something more like:
var doc = document;
function E(id){
return doc.getElementById(id); // you guessed it - same as document.getElementById, without typing it every time
}
var htm = E('htm'), css = E('css'), js = E('js');
contentShow = (function(){ // self-executing scopes off var showing - variable style assignment requires function definition before execution
var showing = false;
return function(){ // returns unexecuted function
var ht = E('ht').style, cs = E('cs').style, jsc = E('jsc').style;
if(showing){
ht.display = cs.display = jsc.display = 'none'; showing = false;
}
else{
ht.display = cs.display = jsc.display = 'block'; showing = true;
}
}
})();
htm.addEventListener('click', contentShow);
css.addEventListener('click', contentShow);
js.addEventListener('click', contentShow);
See updated JSFiddle here.
If there are no other click Events on those Elements, you could even change
htm.addEventListener('click', contentShow);
css.addEventListener('click', contentShow);
js.addEventListener('click', contentShow);
to
htm.onclick = css.onclick = js.onclick = contentShow;
JSFiddle here
but keep in mind this technique overwrites previous Events of the same type.
Here is a variation of #K Scandrett answer which add some scalability/flexibility
var navElements = document.getElementsByClassName("nav");
//Add Event Listeners
for(var i = 0; i < navElements.length; i ++)
{
navElements[i].addEventListener('click', contentShow, false);
}
function contentShow(el) {
var whichOne = el.target.attributes["data-id"].value;
var target = document.getElementById(whichOne);
for(var i = 0; i < navElements.length; i ++)
{
var content = document.getElementById(navElements[i].attributes["data-id"].value)
content.style.display = content === target ? "block" : "none";
}
}
<span data-id="htm" style="margin-right:10px;color:red; cursor:pointer" class="nav">Click to show the HTML Block</span>
<span data-id="css" style="margin-right:10px;color:green; cursor:pointer" class="nav">Click to show the CSS Block</span>
<span data-id="js" style="margin-right:10px;color:blue; cursor:pointer" class="nav">Click to show the JS Block</span>
<br/>
<br/>
<div id="htm">Some HTML info here</div>
<div id="css" style="display:none">Some CSS info here</div>
<div id="js" style="display:none">Some JavaScript info here</div>
I know you're looking for a javascript solution here.and kudos to you for wanting to understand javascript before getting into jquery, but here is an out of the box solution for you.... pure HTML and CSS
.info {display:none;}
.info:target{display:block;}
Click to show the HTML Block
Click to show the CSS Block
Click to show the JS Block
<br/>
<br/>
<div id="htm" class="info">Some HTML info here</div>
<div id="css" class="info">Some CSS info here</div>
<div id="js" class="info">Some JavaScript info here</div>
What I've done here is, leverage internal page id links and the :target selector. In my mind, this is more semantic and can also still be extended by scripting while still maintaining semantics. This option also gives your uses the option of bookmarking selections etc.
CSS OPTION 2
This option achieves the initial display. It is not as clean and uses absolute positioning and z-indexes. Alos note that is uses a background color to conceal the initial option.
.info {position:relative;}
.info > div {
position:absolute;
top:0;
left:0;
background-color:#FFF;
z-index:10;
display: none;
}
#htm
{
display:block;
z-index:1;
}
.info > div:target {
display: block;
}
Click to show the HTML Block
Click to show the CSS Block
Click to show the JS Block
<br/>
<br/>
<div class="info">
<div id="htm">Some HTML info here</div>
<div id="css">Some CSS info here</div>
<div id="js">Some JavaScript info here</div>
</div>
On a side note you should consider adding/removing css classes using javascript instead of the display property directly. This will enable the use of CSS transitions.

Div hide/show toggle issue

I'm currently making an iphone webapp and have almost finished it, I just need to fix this one little issue im having
Ive managed to hide one div layer and show another, but what I would like is for the same button to then show the layer I have hid and hide the one that I have shown when clicked again. So basically clicking the button would take it back to the original state
the code I am currently using is
<script type="text/javascript">
function toggle_layout(d)
{
var onediv = document.getElementById(d);
var divs=['Posts','Posts2'];
for (var i=0;i<divs.length;i++)
{
if (onediv != document.getElementById(divs[i]))
{
document.getElementById(divs[i]).style.display='none';
}
}
onediv.style.display = 'block';
}
</script>
It hides a div I have named "Posts" and shows a div I have named "Posts2", but clicking it again does not reverse the effect.
If you wanna take a look at my site its http://a-m-creativecapture.tumblr.com/
Will have to view it on a mobile to see what I am talking about.
Have you tried style.visibility (visible|hidden) instead of style.display?
Assuming that your divs are something like this:
<div id="posts"></div>
<div id="posts2"></div>
You can use the following code:
var posts = document.getElementById('posts'),
posts2 = document.getElementById('posts2');
function toggle() {
if (this == posts) {
posts.style.display = 'none';
posts2.style.display = 'block';
} else {
posts.style.display = 'block';
posts2.style.display = 'none';
}
}
div1.onclick = toggle;
div2.onclick = toggle;

Apply actual actions to right click context menu

I am trying to use this right-click context menu. It works visually as hoped, however I dont know where to begin to apply actual actions when menu items are clicked. Obviously right now all it says is Back menu item was clicked - target id...., Obiviously when someone clicked back it would actually take them back a page vice just stating what they clicked.
here is the jquery that generates the menu
<script>
var callback = function(target,element){
$(target).html('<span style="color:red">' +$(element).html() +'</span> menu is clicked, Target id: '+ $(target).attr('id'));
};
var menu = {};
menu['back'] = {icon:'icon-arrow-left',text:'Back',click:callback};
menu['forward'] = {icon:'icon-arrow-right',text:'Forward',click:callback};
menu['view'] = {text:'View',click:callback};
menu['sortby'] = {text:'Sort by',click:callback};
menu['refresh'] = {icon:'icon-refresh',text:'Refresh',click:callback};
menu['notepad'] = {text:'Notepad++',click:callback};
menu['s1'] = '---';
menu['copy'] = {text:'Copy',click:callback};
menu['paste'] = {disabled:true,text:'Paste',click:callback};
menu['paste_shortcut'] = {disabled:true,text:'Paste shortcut',click:callback};
menu['s2'] = '---';
menu['create_shortcut'] = {text:'Create shortcut',click:callback};
menu['rename'] = {text:'Rename',click:callback};
menu['del'] = {text:'Delete',click:callback};
menu['s3'] = '---';
menu['properties'] = {text:'Properties',click:callback};
$('#id0').contextMenu(menu);
$('body').contextMenu(menu);
$('body').contextMenu('beforeDisplay',function(target){ console.log(target.html()) });
</script>
Thanks for any help/guidance where to look or how to get started in advance!
Replace
function(target){ console.log(target.html()) }
with a function that performs your actions.

Categories

Resources