Run a Javascript function when clicking outside div1 AND div2 - javascript

Trying to run a Javascript function only if click outside div1 AND div2. If clicked inside div1 or div2, nothing should happen. Any idea how I could achieve that? Example: I would need div2 to be set display: noneand additionally add styles to div1 when clicked outside the divs.
var x = document.getElementById("mega-menu");
document.addEventListener('mouseup', function(e) {
if (!(x.contains(e.target) || document.getElementById("menu-item-136").contains(e.target))) {
x.style.display = 'none';
var elem = document.querySelectorAll("#menu-item-136");
elem.forEach((elem) => {
elem.style.backgroundColor = "red";
});
}
});
This is the furthest I could get. But at the moment, div2 (mega-menu) also gets hidden when clicked on the menu item... Hope you understand what I mean...
Thanks

Can you complete your sample code above? I've added elements to your snippet, but can't duplicate your problem. It seems to be working for me.
Also a couple of off-topic best practices:
the HTML standard doesn't allow for elements with duplicate IDs. If you have more than one element with id #menu-item-136, you should be using a class instead of an ID.
Get both elements outside the event listener...more efficient (like you're already doing with #mega-menu)
Instead of having an if statement with a nested block, do an if...return instead. That way your code is less indented.
var x = document.getElementById('mega-menu');
var y = document.getElementById('menu-item-136');
document.addEventListener('mouseup', function(e) {
if (x.contains(e.target) || y.contains(e.target)) return;
x.style.display = 'none';
y.style.backgroundColor = 'red';
});
div { border: 1px solid black; }
<div id='mega-menu'>mega menu</div>
<div id='menu-item-136'>menu 136</div>

Looks like from this code,
document.querySelectorAll("#menu-item-136");
There are multiple elements with id "menu-item-136" as you are looping through the result.
First of all If there are multiple elements with same Id, It is not a valid HTML.
Thats why
document.getElementById("menu-item-136").contains(e.target)
this results in false, as it may have selected wrong element other that what you have clicked.
Even if you use class to get the elements, it may still fail as querySelector based on class will still results in returning multiple elements.
Instead of checking if your target element is contained in the div's - use a check to see if the element parent hierarchy have class name that you add for menu-item div.
if( e.target.closest(".container-class"))
So now you are just checking if current target have any parent with menu-item's class.

Related

JavaScript focus a particular element with div class, not div id declaration

The following function can focus on an element with an id declaration:
function setFocus() {
document.getElementById("focus").focus();
}
But how can one focus on an element with a classname declaration. Use case would be previously in the code where the element we want to focus on is already stored from the dom (i.e., const element = document.querySelectorAll('.a-class-name')[0]) type of scenario?
Does the element have a tab index? You cannot focus a non input element unless it has a tab index. Use tabindex="-1" for elements like divs and spans. Then call the .focus() method on the element. -1 will allow you to focus with the focus method but wont get focus when move the focus around with the keyboard and pressing tab.
document.getElementById('btn').addEventListener('click', function() {
document.querySelectorAll('.focus_me')[0].focus();
});
<span class="focus_me" tabindex="-1">Focus me</span><br>
<button id="btn">Click to focus</button>
element.scrollIntoView(true) will do what you are needing.
document.getElementsByClassName('className') would always return multiple elements because conceptually Classes are meant to be applied to multiple elements. If you want only the first element in the DOM with that class, you can select the first element out of the array returned, as you did.
var elements = document.getElementsByClassName('className');
var requiredElement = elements[0];
OR
var requiredElement = document.querySelector('.className');
Then as #j08691 mentioned in the comments use
function setFocus() {
requiredElement.focus();
}
If the one with getElementById works, then there is no reason for this to not.
Happy coding. :)

Trying to dynamically show elements that are hidden in the stylesheet with JS

I'm writing a card game in JS that uses an onclick event to decide who goes first. I'm trying to make every other element (contained within 2 divs) hidden until this has happened.
I've tried setting these divs as display:none in the CSS, then using x.style.display = 'block' in the Javascript to make them visible:
let firstGoChosen = 0;
function hideShow() {
let div1 = document.getElementById('divvy1');
let div2 = document.getElementById('divvy2');
if (firstGoChosen === 1) {
div1.style.display = 'block';
div2.style.display = 'block';
}
}
The function called by the onclick event sets firstGoChosen = 1
I've also tried this using visibility:hidden but neither have worked so far.
I'm only using pure JS for this as I'm not learning jQuery yet.
Here's the JSfiddle for anybody feeling brave...
You are trying to use css class names as id's, that's what is not working. You can fix this by either adding an id
<div class="divvy1" id="divvy1">
and continuing to use getElementById() or you can look into using getElementsByClassName() which functions a little differently but looks more to be what you are trying to accomplish.
To achieve expected result , use getElementsByClassName , as you are using class and trying with document.getElementById
document.getElementsByClassName returns array of elements with matching classname i.e divvy1 and divvy2, as there is one element choose first by [0]
let div1 = document.getElementsByClassName('divvy1')[0];
let div2 = document.getElementsByClassName('divvy2')[0];
https://codepen.io/nagasai/pen/MGpNoR
Option 2 is to change class to ids and use same javascript code to make work
I’m pretty sure you can do this easily by:
document.querySelectorAll(‘.thoseElements:nth-child(even)’)
.forEach(function (el) {
el.style.display = ‘none’;
});

How to swap placement of two elements, including their classes/ids with onclick?

I'm trying to switch the positions of two divs with an onclick event.
The divs have the same basic format (width, height), but an additional class and id change the way they look.
So, I have two functions that successfully change the id and class names, but there is no visual change.
Here they are:
function whenClickedFilled(){
console.log("filled");
this.firstElementChild.id = "empty";
this.firstElementChild.className = "puzzlepiece emptyDivClass";
}
function whenClickedEmpty(){
console.log("empty");
this.firstElementChild.id = "filled";
this.firstElementChild.className = "puzzlepiece";
}
I'd like to know what the best way is to alternate between classes/ids onclick.
Here is my js fiddle.
I think what you're really looking to do is not swaping the class and id, but swap the elements themselves. This will make sure the numbers contained within the div's is also transfer with the swap.
You still need to implement the logic checks to see if the element should be able to swap with the empty block and there looks like theres a bug when you click empty space itself. But, this should get you on the right track. I recommend placing a debugger statement to step through the code with dev tools open. It will help understand whats taking place. Good luck.
function whenClickedFilled(){
console.log("filled");
//Get the div element and parent
//Then determine the parent of the empty div
var clickedDiv = this.firstChild; //this refers to the TD clicked, get the child div element
var clickedDivParent = this; //this is TD
var emptyDivParent = emptyDiv.parentElement; //stored the empty div reference into a global, retrieve the parent as this could change
//Remove the empty and clicked div's from their container
emptyDivParent.removeChild(emptyDiv)
clickedDivParent.removeChild(clickedDiv);
//Add the elements back to the containers but swapped
clickedDivParent.appendChild(emptyDiv);
emptyDivParent.appendChild(clickedDiv);
}
http://jsfiddle.net/tWrD2/
I'm trying to switch the positions of two divs with an onclick event
If you want to swap two adjacent nodes, you can do something as simple as:
function swapAdjacent(el0, el1) {
el0.parentNode.insertBefore(el1, el0);
}
If you want to swap any two elements in the DOM, you can do something like:
// Swap the postion in the DOM of el0 and el1
function swapElements(el0, el1) {
// Create a temp node that can replace el0
var tmp = el0.cloneNode(false);
// Replace el0 with tmp
el0.parentNode.replaceChild(tmp, el0);
// Replace el1 with el0
el1.parentNode.replaceChild(el0, el1);
// Replace temp node with el1
tmp.parentNode.replaceChild(el1, tmp);
}
and some test markup:
<div id="d0">div 0</div>
<div id="d1">div 1</div>
<button onclick="
swapElements(document.getElementById('d0'), document.getElementById('d1'));
">Swap d0, d1</button>
<button onclick="
swapAdjacent(document.getElementById('d0'), document.getElementById('d1'));
">Swap adjacent</button>
Of course the two elements to swap must be consistent with the surrounding elements, e.g. you can't swap an option element with a div and expect everything to work, but you can probably swap a span with a div.
If you want to swap elements by clicking on one or the other:
<div id="d0" onclick="swapElements(this, document.getElementById('d1'))">div 0</div>
<div id="d1" onclick="swapElements(this, document.getElementById('d0'))">div 1</div>
I found a nice solution provided by fuell when I was searching fo an actual html swap:
<div id="div_1">THIS IS DIV 1</div>
<div id="div_2">THIS IS DIV 2</div>
Go Swap!
$(document).ready(function() {
$(".go-swap").click(function() {
$("#div_1").removeAttr("style");
$("#div_2").removeAttr("style");
var tmp = $("#div_1").html();
$("#div_1").empty().append($("#div_2").html());
$("#div_2").empty().append(tmp);
});
});

List Items show javascript functions on only 1st item (Items have same ID)

I'm making an ul and each li has the same ID to keep the code simple, clean, and efficient.
When I apply my scripting functions they only apply to the first li.
How do I apply the functions to the li that is hovered?
Thank you
JSFIDDLE
It is incorrect to have more than one Element with the same id. Since document.getElementById relies the fact that there is only one element with an id, it will not do what you expect. You should change the code to use class instead of id.
Alternatively you could use querySelector instead which makes no assumptions regarding the id:
function openHiddenItems(evt) {
if (evt.target.id !== 'list-item') return;
evt.target.querySelector('#red-square').style.visibility = 'visible';
evt.target.querySelector('#yellow-circle').style.visibility = 'visible';
}
function closeHiddenItems(evt) {
if (evt.target.id !== 'list-item') return;
evt.target.querySelector('#red-square').style.visibility = 'hidden';
evt.target.querySelector('#yellow-circle').style.visibility = 'hidden';
}
Also make sure you pass the event to your open and close functions. I would recomend separating JS code and HTML:
var elements = document.querySelectorAll('#list-item');
for (var i=0; i<elements.length; i++) {
elements[i].addEventListener('mouseover', openHiddenItems);
elements[i].addEventListener('mouseout', closeHiddenItems);
}
EDIT: There is a back-forth between the functions if you hover over the place the elements become visible/hidden. It can be solved as well, by seeing if the currently hovered element is inside the #list-item.
Here is a demo: http://jsfiddle.net/GfqDj/11/

Toggling elements with JavaScript

I want to toggle a div element (expand/collapse) when clicked.
I have many div elements, on click to new element, I want to collapse the previous one and expand the current clicked one.
I tried using static type variable to save the instance of previous div tag and compared with the current selection, but I don't know why is it not working.
Searching about this, I got similar code idea to collapse all div and then expand the current selected only, but I want to just toggle the previous one with new one, not collapse all div and expand the selected (though I would be using it if other way is not possible)
Can it be done using static variables of js?
At its simplest, you can simply do something like this:
var divs = document.getElementsByTagName('div'),
collapseClass = 'collapsed',
current = divs[0];
// Hide all elements except first, add click event hander
for(var i = 0, len = divs.length; i < len; i++){
divs[i].onclick = function(){
if(this !== current){
toggle(this, current);
current = this;
}
};
if(i > 0) toggle(divs[i]);
}
This will store the current element in a variable, then toggle it when another element is clicked. It also uses an if statement to check if the currently clicked element is the one currently visible element, and only toggles if its not.
See a working demo of this here: http://jsfiddle.net/GaxvM/
You can assign a unique ID to each of the elements and use document.getElementById to identify both elements, and then collapse one/expand the other.
If you number them sequentially (like div1, div2, div3, etc) you could do something like:
function colexp(div_id){
div_2_collapse = document.getElementById(div_id);
next_div = div_id.substr(0,3) + parseInt(div_id.substr(3))+1;
div_2_expand = document.getElementById(next_div);
hide(div_2_collapse);
show(div_2_expand);
}

Categories

Resources