Simple HTML Javascript button onclick function not working - javascript

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>

Related

Disable dropdown item with CSS or Javascript

I need to disable, deactivate or at least hide a dropdown item called Private request and I can only use CSS or Javascript to do so.
When I inspect the dropdown item it has the class a.js-dropdown-list. But every item in my dropdown has this class. So I can't just use {display: none;} because it will hide all options. Is there no more specific ID for every item in the drop down or can I deactivate items with Javascript?
Drop Down looks like this:
Here the code (1st block is for the picker field, 2nd for the drop-down menue):
<div id="js-organization-picker">
<sd-select class="js-share-with-organisation-picker is-private" data-type="link" data-id="customfield_10203" data-value="38" data-options="[{"label":"Private request","styleClass":"is-private","icon":"locked"},{"label":"Share with Testorganisation","value":38,"icon":"unlocked"}]" resolved="">
<a id="js-customfield_10203-dropdown-trigger" class="aui-dropdown2-trigger aui-button aui-button-link js-trigger customfield_10203-trigger select-dropdown-trigger aui-alignment-target aui-alignment-element-attached-top aui-alignment-element-attached-left aui-alignment-target-attached-bottom aui-alignment-target-attached-left active aui-dropdown2-active aui-alignment-enabled" aria-controls="customfield_10203-dropdown" aria-haspopup="true" role="button" tabindex="0" data-aui-trigger="" data-dropdown2-hide-location="js-customfield_10203-dropdown-container" resolved="" aria-expanded="true" href="#customfield_10203-dropdown">
<span class="aui-icon aui-icon-small aui-iconfont-locked">
: : before
</span> Private request
: : after
</a>
<input name="customfield_10203" type="hidden" class="js-input" value="">
<div id="js-customfield_10203-dropdown-container" class="hidden"></div>
</sd-select>
</div>
<div id="customfield_10203-dropdown" class="aui-dropdown2 filter-dropdown aui-style-default js-filter-dropdown select-dropdown aui-layer aui-alignment-element aui-alignment-side-bottom aui-alignment-snap-left aui-alignment-element-attached-top aui-alignment-element-attached-left aui-alignment-target-attached-bottom aui-alignment-target-attached-left aui-alignment-enabled" role="menu" aria-hidden="false" data-id="customfield_10203" resolved="" style="z-index: 3000; top: 0px; left: 0px; position: absolute; transform: translateX(602px) translateY(918px) translateZ(0px);" data-aui-alignment="bottom auto" data-aui-alignment-static="true">
<div role="application">
<ul class="aui-list">
<li>
<a class="js-dropdown-item " href="#">Private request</a>
</li>
<li></li>
<li>
<a class="js-dropdown-item " href="#" data-value="38">Share with Testorganisation</a>
</li>
<li></li>
</ul>
</div>
</div>
E.g. you could give the dropdown item ids to identify them. In HTML this would look like this: <p id="yourIdHere"></p>
You can access this item through Javascript using the document.getElementById() function like this: document.getElementById('yourIdHere').style.display = 'none';
If you can't edit the existing html code, youi have to get the element by it's name/value. This is a bit difficult. You have to iterate through all elements of that type and evaluate each name/value. If you have found the one, you was looking for, you can edit/hide it. You would do so (untested):
var elements = document.getElementsByTagName('div'); //div will be the name of the tag of your elements in the dropdown list
var length = elements.length;
for (var i=0, item; item = elements[i]; i++) {
if(item.value == "Private request") { //"Private request" is the name of the element we are looking for
item.style.display = 'none'; //Hide the element
}
}
You could loot trough all 'js-dropdown-items', check its innerText for 'Private request' and set its parentNodes display-property to 'none':
var list = document.getElementsByClassName('js-dropdown-item');
for(var i = 0; i < list.length; i++){
if(list[i].innerText === 'Private request') list[i].parentNode.style.display = 'none';
}
<ul class="aui-list">
<li>
<a class="js-dropdown-item " href="#">Private request</a>
</li>
<li></li>
<li>
<a class="js-dropdown-item " href="#" data-value="38">Share with Testorganisation</a>
</li>
<li></li>
</ul>
VannillaJS Solution document.querySelectorAll(".aui-list > li")[0].style.display = "none";
Welcome!
If I get you right there are plenty of elements with the same ID js-dropdown-list and you want to hide a specific one and there is no additional class for the element and you're not allowed to add specificity to it, let's say by adding of an additional class, you can do the following:
Grab all elements with this id by:
let elements = document.querySelectorAll('.js-dropdown-list'); // this is an array of these elements
let elementToHide = elements[n] // whene n is the number of that element
//hiding the element
elementToHide.style.display = 'none';
Hope that helps!
NOTE: I believe you will have to actually hide it OR use whatever you are using for this pseudo drop down (there was no reference in the question) to manage the disabled state if it provides that. Reference: https://www.w3.org/TR/2014/REC-html5-20141028/disabled-elements.html
Get the element by its text and then hide it. Might need the parent but this directly answers the question. Note this could all be wrapped in a function and then called from where you wish.
function HideByText(elId, findText) {
let group = document.getElementById(elId).getElementsByClassName('js-dropdown-item');
let found = Array.prototype.filter.call(group, function(el) {
return el.innerText === findText;
});
found.forEach(function(el) {
el.style.display = 'none';
});
return found;// in case you need the elements ref.
}
let foundFiltered = HideByText('customfield_10203-dropdown', 'Private request');
<div id="customfield_10203-dropdown" class="aui-dropdown2 filter-dropdown aui-style-default js-filter-dropdown select-dropdown aui-layer aui-alignment-element aui-alignment-side-bottom aui-alignment-snap-left aui-alignment-element-attached-top aui-alignment-element-attached-left aui-alignment-target-attached-bottom aui-alignment-target-attached-left aui-alignment-enabled"
role="menu" aria-hidden="false" data-id="customfield_10203" resolved="" data-aui-alignment="bottom auto" data-aui-alignment-static="true">
<div role="application">
<ul class="aui-list">
<li>
<a class="js-dropdown-item " href="#">Private request</a>
</li>
<li></li>
<li>
<a class="js-dropdown-item " href="#" data-value="38">Share with Testorganisation</a>
</li>
<li></li>
</ul>
</div>
</div>
Alternate for parent would be:
Change el.style.display = 'none'; to
if (node.parentElement) {
el.parentElement.style.display = 'none';
}
Have you tried using CSS? Not an ideal solution, but it might be better than using JS for this.
#js-organization-picker + .aui-dropdown2 .aui-list li:first-child {
display: none;
}
If you need to hide the first 2 elements, you could do something like:
#js-organization-picker + .aui-dropdown2 .aui-list li:first-child,
#js-organization-picker + .aui-dropdown2 .aui-list li:first-child + li {
display: none;
}

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.

Get closest element with given id using javascript

I need to add a class to the closest div with a given id after I click the div above it. My example below should make more sense of what I need.
<style>
.menuContent {display:none;}
.expandMenu {display:inherit;}
</style>
<ul>
<li>
<div class="menuIcon" onclick="expandMenu('menuContent');">+</div>
<div id="menuContent" class="menuContent">
<p>This</p>
<p>That</p>
<p>The Other</p>
</div>
</li>
<li>
<div class="menuIcon" onclick="expandMenu('menuContent');">+</div>
<div id="menuContent" class="menuContent">
<p>This</p>
<p>That</p>
<p>The Other</p>
</div>
</li>
</ul>
This is the script I have so far that searches the class names of the given element and adds or removes the 'expandMenu' class when clicked.
<script>
function expandMenu(x) {
var d = document.getElementById(x);
var c = d.className;
if (c.search("expandMenu") === -1) {
d.className += " expandMenu";
} else {
d.className = c.replace(" expandMenu","");
}
}
</script>
This is all working fine, the issue is when clicking the 'menuIcon' in the second 'li', it's the first 'li' element that the script is applied too - it's obviously just finding the first 'menuContent' and applying the className function to it.
How can I limit the function to only apply to the 'menuContent' div that is directly after it.
I don't want to use jQuery either - good ol' fashioned plain Javascript would be great.
Give the menu icons unique ids, and pass that id to the function. Toggle based on the id, instead of the class. You are right, it is choosing the first one because it has found it when running through the code.
You should not have the same id on multiple elements. Try changing one of the id's and passing the new id to the function.
<style>
.menuContent {display:none;}
.expandMenu {display:inherit;}
</style>
<ul>
<li>
<div class="menuIcon" onclick="expandMenu('menuContent1');">+</div>
<div id="menuContent1" class="menuContent">
<p>This</p>
<p>That</p>
<p>The Other</p>
</div>
</li>
<li>
<div class="menuIcon" onclick="expandMenu('menuContent2');">+</div>
<div id="menuContent2" class="menuContent">
<p>This</p>
<p>That</p>
<p>The Other</p>
</div>
</li>
</ul>

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))

Weird behavior with .parents() and .closest() when trying to return parent <ul> element id in jQuery

So I've got 2 <ul> containers each with id's. Inside of them are a list of <li> elements.
The first <ul> is <ul id="coaches-list">. The second is <ul id="players-list">.
There are tags within each <li> that have an id called close (which is a link that I'm using as my selector), which will delete each <li> node once clicked. I'm trying to target each <ul> container to see where it is coming from.
My HTML is:
<!-- coaches box -->
<div class="box">
<div class="heading">
<h3 id="coaches-heading">Coaches</h3>
<a id="coaches" class="filter-align-right">clear all</a>
</div>
<ul id="coaches-list" class="list">
<li><span>Hue Jackson<a class="close"></a></span></li>
<li class="red"><span>Steve Mariuchi<a class="close"></a> </span></li>
</ul>
</div>
<!-- players box -->
<div class="box">
<div class="heading">
<h3 id="players-heading">Players</h3>
<a id="players" class="filter-align-right">clear all</a>
</div>
<ul id="players-list" class="list">
<li><span>Steve Young<a class="close"></a></span></li>
<li><span>Gary Plummer<a class="close"></a></span></li>
<li><span>Jerry Rice<a class="close"></a></span></li>
</ul>
</div>
My remove tag function in jQuery is:
function removeSingleTag() {
$(".close").click(function() {
var $currentId = $(".close").closest("ul").attr("id");
alert($currentId);
// find the closest li element and remove it
$(this).closest("li").fadeOut("normal", function() {
$(this).remove();
return;
});
});
}
Whenever I click on each specific tag, it's removing the proper one I clicked on, although when I'm alerting $currentId, if I have:
var $currentId = $(".close").closest("ul").attr("id");
It alerts 'coaches-list' when I'm clicking on a close selector in both <ul id="coaches-list" class="list"></ul> and <ul id="players-list" class="list"></ul>
If I change that to:
var $currentId = $(".close").parents("ul").attr("id");
It has the same behavior as above, but alerts 'players-list', instead.
So when using closest(), it's returning the very first <ul> id, but when using parents(), it's returning the very last <ul> id.
Anyone know what is going on with this whacky behavior?
It's expected behavior.
You should use:
var $currentId = $(this).closest("ul").attr("id");
$(this) points at the clicked .close.
$(".close") points at the first one found.
It's because you run that selector from click handler you should use this instead:
var $currentId = $(this).closest("ul").attr("id");
Try using this function to get the parent:
var $currentId = $(this).parents().first();
I've never used the .closest() function but according to jQuery what you have specified should work. Either way, try that out and tell me how it goes.
You also need to make it so that it selects the current element by using $(this)

Categories