Make div in div clickable with Javascript - javascript

Have a problem and can't get to solve it. Tried to use QuerySelectorAll and comma separating with GetElementsByClassName, but that didn't work, so I am wondering how to solve this problem.
I have this HTML:
<div class="area">Test title
<div class="some content" style="display: none">blablbala
<input></input>
</div>
<div class="two">This should be clickable too</div>
</div>
<div class="area">
Test title
<div class="some content">
blablbala
<input></input>
</div>
<div class="two">This should be clickable too</div>
</div>
JS:
function areaCollapse() {
var next = this.querySelector(".content");
if (this.classList.contains("open")) {
next.style.display = "none";
this.classList.remove("open");
} else {
next.style.display = "block";
this.classList.add("open");
}
}
var classname = document.getElementsByClassName("area");
for (var i = 0; i < classname.length; i++) {
classname[i].addEventListener('click', areaCollapse, true);
}
http://jsfiddle.net/1BJK903/nb1ao39k/6/
CSS:
.two {
position: absolute;
top: 0;
}
So now, the div with classname "area" is clickable. I positioned the div with class "two" absolute and now the whole div is clickable, except where this other div is. If you click on the div with classname "two", it doesn't work (it does not collapse or open the contents). How can I make this work, without changing the structure?

One way is using a global handler, where you can handle more than one item by checking its id or class or some other property or attribute.
Below snippet finds the "area" div and pass it as a param to the areaCollapse function. It also check so it is only the two or the area div (colored lime/yellow) that was clicked before calling the areaCollapse.
Also the original code didn't have the "open" class already added to it (the second div group), which mean one need to click twice, so I change the areaCollapse function to check for the display property instead.
function areaCollapse(elem) {
var next = elem.querySelector(".content");
if (next.style.display != "none") {
next.style.display = "none";
} else {
next.style.display = "block";
}
}
window.addEventListener('click', function(e) {
//temp alert to check which element were clicked
//alert(e.target.className);
if (hasClass(e.target,"area")) {
areaCollapse(e.target);
} else {
//delete next line if all children are clickable
if (hasClass(e.target,"two")) {
var el = e.target;
while ((el = el.parentElement) && !hasClass(el,"area"));
if (targetInParent(e.target,el)) {
areaCollapse(el);
}
//delete next line if all children are clickable
}
}
});
function hasClass(elm,cln) {
return (" " + elm.className + " " ).indexOf( " "+cln+" " ) > -1;
}
function targetInParent(trg,pnt) {
return (trg === pnt) ? false : pnt.contains(trg);
}
.area {
background-color: lime;
}
.two {
background-color: yellow;
}
.area:hover, .two:hover {
background-color: green;
}
.some {
background-color: white;
}
.some:hover {
background-color: white;
}
<div class="area">Test title clickable 1
<div class="some content" style="display: none">blablbala NOT clickable 1
</div>
<div class="two">This should be clickable too 1</div>
</div>
<div class="area">Test title clickable 2
<div class="some content">blablbala NOT clickable 2
</div>
<div class="two">This should be clickable too 2</div>
</div>
<div class="other">This should NOT be clickable</div>

You need to find your two elements while you're binding classname, and bind that as well.
var classname = document.getElementsByClassName("area");
for(var i=0; i < classname.length; i++){
classname[i].addEventListener('click', areaCollapse, true);
var twoEl = classname[i].getElementsByClassName("two")[0];
twoEl.addEventListener('click', function(e) { console.log('two clicked'); });
}

If you want to use jQuery:
$('.two').click(function(){
//action here
});

Related

change properties of two divs with one onclick and querySelectorAll()

I have multiple elements that are seperatet in two divs. The first div contains a Text and the second div a color.
When I click on one element the text and color should change and if I click it again it should change back.
The problem is that no matter which one I click, its always the last one which changes.
The HTML part:
<style>
.colorGreen {
background-color: green;
}
.colorRed {
background-color: red;
}
</style>
<div class="box2">Text1</div>
<div class="box1 colorGreen">O</div>
<div class="box2">Text1</div>
<div class="box1 colorGreen">O</div>
<div class="box2">Text1</div>
<div class="box1 colorGreen">O</div>
The JavaScript part:
<script type='text/javascript'>
var box1Temp = document.querySelectorAll(".box1");
var box2Temp = document.querySelectorAll(".box2");
for (var i = 0; i < box1Temp.length; i++) {
var box1 = box1Temp[i];
var box2 = box2Temp[i];
box2.onclick = box1.onclick = function() {
if (box1.classList.contains("colorGreen")) {
box1.classList.add("colorRed");
box1.classList.remove("colorGreen");
box2.innerHTML = "Text2";
} else {
box1.classList.add("colorGreen");
box1.classList.remove("colorRed");
box2.innerHTML = "Text1";
}
}
}
</script>
It works, when I use only one div.
Then I can use 'this', instead of the 'box1' variable, to addres the right element.
But if I replace 'box1' with 'this' its still the text div that changes.
(I know it's obvious that this is happening, but I'm lost)
With a few small tweaks, this can be written a lot more cleanly:
// Capture click event for parent container, .toggle-set
for (const ele of document.querySelectorAll(".toggle-set")) {
ele.addEventListener("click", function() {
// Grab text and color elements
const textToggle = ele.querySelector(".toggle-text");
const colorToggle = ele.querySelector(".toggle-color");
// Toggle text
// NOTE: This could use further refinement with regex or something similar to strip whitespace before comparison
textToggle.textContent = textToggle.textContent == "Text1" ? "Text2" : "Text1";
// Toggle css classes
colorToggle.classList.toggle("colorGreen");
colorToggle.classList.toggle("colorRed");
});
}
.colorGreen { background-color: green; }
.colorRed { background-color: red; }
<div class="toggle-set">
<div class="toggle-text">Text1</div>
<div class="toggle-color colorGreen">
O
</div>
</div>
<div class="toggle-set">
<div class="toggle-text">Text1</div>
<div class="toggle-color colorGreen">
O
</div>
</div>
Your code is so confused
You were right for the this option.
you can do with simple onclick function :
function change(el){
box1 = el.querySelector('.box1');
box2 = el.querySelector('.box2');
if (box1.classList.contains("colorGreen")) {
box1.classList.add("colorRed");
box1.classList.remove("colorGreen");
box2.innerHTML = "Text2";
} else {
box1.classList.add("colorGreen");
box1.classList.remove("colorRed");
box2.innerHTML = "Text1";
}
}
<style>
.colorGreen {
background-color: green;
}
.colorRed {
background-color: red;
}
</style>
<div onclick="change(this)">
<div class="box2">Text1</div>
<div class="box1 colorGreen">O</div>
</div>
<div onclick="change(this)">
<div class="box2">Text1</div>
<div class="box1 colorGreen">O</div>
</div>
<div onclick="change(this)">
<div class="box2">Text1</div>
<div class="box1 colorGreen">O</div>
</div>
I think following code snippet would help you to get your desired result
let box1 = document.querySelectorAll(".box1");
let box2 = document.querySelectorAll(".box2");
box1.forEach((b1,i) => {
b1.addEventListener("click",(ev) => {
ev.target.classList.toggle("colorGreen");
ev.target.classList.toggle("colorRed");
console.log(box2[i]);
if(ev.target.classList.contains("colorGreen")){
box2[i].textContent = "Text1";
}else{
box2[i].textContent = "Text2"
}
})
})

How to select which div to display by id?

I have a code written like this. I would like the myDIV1 to display when I click the first section with 'HELLO' quote, and myDIV2 when second section 'HI' is clicked.
Tried using event.target to change javascript var X into myDIV1 or myDIV2 but not so sure if my syntax used is correct or if the logic I tried can be possible.
I would like to change var x = document.getElementbyId( 'either of the two divs here' )
when 1st section or 2nd section is click. (sorry for the bad grammar)
html
<section class="news"> HELLO
</section>
<section class="news"> HI
</section>
<div class="divelement "id="myDIV1">
This is my DIV1 element.
</div>
<div class="divelement "id="myDIV2">
This is my DIV2 element.
javascript
<script>
function myFunction() {
var x = document.getElementById("myDIV");
if (x.style.display === "none") {
x.style.display = "block";
y.style.display = "block";
} else {
x.style.display = "none";
y.style.display = "none";
}
}
</script>
You can do it by this way using jQuery.
jQuery('.news').click(function(){
var target = jQuery(this).attr('data-target');
jQuery('.divelement').hide(); /*hide all divelement*/
jQuery(target).toggle(); /*Show the targeted divelement*/
console.log('Show' + target);
});
.divelement{
display: none; /* By default divelement will be hidden */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="news" data-target="#myDIV1"> HELLO
</section> <!-- set targeted div id in data-target attribute -->
<section class="news" data-target="#myDIV2"> HI
</section>
<div class="divelement "id="myDIV1">
This is my DIV1 element.
</div>
<div class="divelement "id="myDIV2">
This is my DIV2 element.
</div>
Here you don't need id-s at all. Can make simple tabs with already existing classes:
let news = document.querySelectorAll('.news');
let divs = document.querySelectorAll('.divelement');
// saved element lists to variables
// `news[0]` — the first element, `news[1]` — second, etc.
let prev = 0; // index of previous clicked section
for( let i = 0; i < news.length; i++ ){
// Google → for loop, JS for loop let
news[i].addEventListener('click', function(){
news[prev].classList.remove('active');
divs[prev].classList.remove('active');
// removing class from last section and div
news[i].classList.add('active');
divs[i].classList.add('active');
// adding to current clicked, by index ( `i` - exact number, got from `for` )
prev = i; // updating previous clicked index
});
}
.divelement {
display: none;
margin: 5px;
padding: 5px;
border: 2px solid orange;
}
.news { cursor: pointer; margin: 5px; }
.divelement.active {
display: block;
}
.news.active {
color: red;
}
<section class="news">HELLO</section>
<section class="news">HI</section>
<section class="news">BUBU</section>
<div class="divelement">HELLO</div>
<div class="divelement">HI</div>
<div class="divelement">BUBU</div>
If you are 100% sure, that there will be only two elements, can use such trick:
let news = document.querySelectorAll('.news');
let divs = document.querySelectorAll('.divelement');
setDivToggle(0);
setDivToggle(1);
function setDivToggle(index) {
news[index].addEventListener('click', function(){
let hide = +!index; // (*1)
divs[index].style.display = "block";
divs[hide].style.display = "none";
});
}
.news { cursor: pointer; margin: 10px; }
.divelement { display: none; }
<section class="news"> HELLO </section>
<section class="news"> HI </section>
<div class="divelement"id="myDIV1">DIV1 element.</div>
<div class="divelement"id="myDIV2">DIV2 element.</div>
(*1) let hide = +!index; — clicked index always will be 0 or 1.
In boolean expressions, 0 == false, 1 == true.
! — logical "NOT" operator. Converts false → true and vice versa.
+ converts the result into number.
Little demo:
console.log( +false ) // 0
console.log( +true ) // 1
console.log( !0 ) // true
console.log( !1 ) // false
console.log( +!0 ) // 1
console.log( +!1 ) // 0
In fact, it's just twisting 1 with 0 and 0 with 1.

Tie children of one div to children of another div with jquery

I have two parent divs: .inputs and .infoBoxes. Each of them have an equal number of children. When the user clicks into the first .input in .inputs, the first .infoBox in .infoBoxes should slideDown(). Same for second, third, etc. I'd like to do this without re-writing the same code for each pair. So far I have:
var $inputs = $('.inputs').children();
var $infoBoxes = $('.infoBoxes').children();
for(var i = 0; i < $inputs.length; i++ ) {
$($inputs[i]).find('.input').focus(function() {
$($infoBoxes[i]).slideDown();
})
$($inputs[i]).find('.input').blur(function() {
$($infoBoxes[i]).slideUp();
})
}
This isn't working but I have tried replacing i with the indexes of each div.
$($inputs[0]).find('.input').focus(function() {
$($infoBoxes[0]).slideDown();
})
$($inputs[0]).find('.input').blur(function() {
$($infoBoxes[0]).slideUp();
})
repeat...
repeat...
repeat...
This works but isn't very DRY. I'm looking for a better solution that won't have me repeating a bunch of code.
First code will not work, because you using same variable for all internal functions. You should wrap it into function, which will create local variable for index. Try following code:
var $inputs = $('.inputs').children();
var $infoBoxes = $('.infoBoxes').children();
for(var i = 0; i < $inputs.length; i++ ) {
(function(ix) {
$($inputs[ix]).find('.input').focus(function() {
$($infoBoxes[ix]).slideDown();
})
$($inputs[ix]).find('.input').blur(function() {
$($infoBoxes[ix]).slideUp();
})
})(i);
}
slideDown is used for showing elements. I am guessing you want to hide elements, since you are clicking on them and you cant click an hidden element. Use hide or slideUp to hide elements.
$(".input, .infobox").on("click", function() {
var ind = $(this).index();
$(".infobox:eq(" + ind + "), .input:eq(" + ind + ")").hide(500);
});
.input,
.infobox {
widht: 100%;
height: 50px;
text-align: center;
margin: 5px 0;
color: white;
}
.input {
background: red;
}
.infobox {
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="inputs">
<div class="input">1</div>
<div class="input">2</div>
<div class="input">3</div>
<div class="input">4</div>
<div class="input">5</div>
</div>
<div class="infoboxes">
<div class="infobox">1</div>
<div class="infobox">2</div>
<div class="infobox">3</div>
<div class="infobox">4</div>
<div class="infobox">5</div>
</div>

Add class to an element without an id

I have a list of items:
<div class="crew-item>
<div class="crew-grid"></div>
<div class="crew-detail></div>
</div>
<div class="crew-item>
<div class="crew-grid"></div>
<div class="crew-detail></div>
</div>
<div class="crew-item>
<div class="crew-grid"></div>
<div class="crew-detail></div>
</div>
When I click on a selected 'crew-grid' I'd like to add a class ('active') to its 'crew-item' parent, but I have no idea how to achieve that using vanilla js or jQuery.
The goal is to reveal the 'crew-detail' part, with active class added to its parent.
Like this?:
$('.crew-grid').on('click', function () {
$(this).closest('.crew-item').addClass('active');
});
Basically, starting from the clicked element, get the closest ancestor element which matches that selector. You don't need an id to target an element, just a way to identify it based on the information you have (in this case the clicked element).
If you want to de-activate other elements at the same time:
$('.crew-grid').on('click', function () {
$('.crew-item').removeClass('active');
$(this).closest('.crew-item').addClass('active');
});
Using jQuery :
$('.crew-grid').click(function() {
$(this).closest('.crew-item').addClass('active');
});
Use Document.querySelectorAll()
var crews = document.querySelectorAll('.crew-item');
if (crews) {
for (var i = 0; i < crews.length; i++) {
var grid = crews[i].querySelector('.crew-grid');
grid.addEventListener('click', toggleActive, false);
}
}
function toggleActive() {
var grids = document.querySelectorAll('.crew-item');
for (var i = 0; i < grids.length; i++) {
if (grids[i].classList.contains('active')) {
grids[i].classList.remove('active');
}
}
this.parentNode.classList.add('active');
}
.crew-item.active {
background: #DDD;
}
.crew-grid:hover {
cursor: pointer;
background: #eee;
}
<div class="crew-item active">
<div class="crew-grid">crew-grid</div>
<div class="crew-detail">crew-detail</div>
</div>
<br>
<div class="crew-item">
<div class="crew-grid">crew-grid</div>
<div class="crew-detail">crew-detail</div>
</div>
<br>
<div class="crew-item">
<div class="crew-grid">crew-grid</div>
<div class="crew-detail">crew-detail</div>
</div>

Pure JS // Hide div when another divs class has been changed

Note: I can't use jQuery, only vanilla javascript
I'm not really fluent in pure JS. And this time I can't use any external resources (like jquery).
What I need:
If div1 class is active, hide text2
If div2 class is active, hide text1
I made it somehow to work, but my JS doesn't trigger when the class changes dynamic with another javascript code.
Code that triggers the active class
function activeClass(elem) {
var a = document.getElementsByClassName('item')
for (i = 0; i < a.length; i++) {
a[i].classList.remove('active')
}
elem.classList.add('active');
}
Code that should trigger hide/show when the class changes
if (document.querySelector(".text2").classList.contains("active")) {
document.getElementsByClassName('text1s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text2s')[0].style.visibility = 'visible';
}
if (document.querySelector(".text1").classList.contains("active")) {
document.getElementsByClassName('text2s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text1s')[0].style.visibility = 'visible';
}
What did I do wrong?
Codepen demo
Place your conditions inside click handler.
Add inline visibility style for inactive element
function activeClass(elem) {
var a = document.getElementsByClassName('item')
for (i = 0; i < a.length; i++) {
a[i].classList.remove('active')
}
elem.classList.add('active');
if (document.querySelector(".text2").classList.contains("active")) {
document.getElementsByClassName('text1s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text2s')[0].style.visibility = 'visible';
}
if (document.querySelector(".text1").classList.contains("active")) {
document.getElementsByClassName('text2s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text1s')[0].style.visibility = 'visible';
}
}
body {
margin: 3em;
}
.item {
cursor: pointer;
}
a {
padding: 10px;
}
.active {
color: red;
border: 1px solid red;
}
<a class="item text1" onclick="activeClass(this)">show text</a>
<a class="item text2 active" onclick="activeClass(this)">hide text</a>
<br>
<br>
<h1 class="text1s" style='visibility:hidden;'>TEXT 1</h1>
<h1 class="text2s">TEXT 2</h1>
Updated Codepen

Categories

Resources