Issues with using classList to hide and show elements - javascript

I need to implement a feature where a div shows up when another div is clicked and should hide if the div is clicked again.
Here is the fiddle with a small portion of the code : https://jsfiddle.net/6dgL6zqb/1/
var portfolio = document.getElementById('portfolio');
EventUtil.addHandler(portfolio, 'click', function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
switch(target.id) {
case 'kk':
console.log('kk clicked');
var idName = target.id + 'Details',
doc = document,
currentProject = doc.getElementById(idName),
otherProjects = doc.getElementsByClassName('projectDetails');
console.log(currentProject);
for (var i = otherProjects.length - 1; i >= 0; i--) {
var projectClassList = otherProjects.item(i).classList;
if (projectClassList.contains('showMe')) {
projectClassList.remove('showMe');
projectClassList.add('hideMe');
}
};
var currentProjectClassList = currentProject.classList;
console.log(currentProjectClassList);
if (!currentProjectClassList.contains('showMe')) {
currentProjectClassList.remove('hideMe');
currentProjectClassList.add('showMe');
} else {
currentProjectClassList.remove('showMe');
currentProjectClassList.add('hideMe');
}
break;
}
});
I am using an EventUtil handler to handle events, along-with event delegation.
So, when I click on Section 1 with the id 'kk', another div with id 'kkDetails' displays. But, I expect the div with id 'kkDetails' to disappear when I click on the div with id 'kk'. How can I get that to happen?
As far as I can see, the currentProjectClassList object is not updating as I expect. Although, I don't understand why.
PS: I am new at programming, so please bear with any ignorance.

There problem that you are having is this section:
otherProjects = doc.getElementsByClassName('projectDetails');
for (var i = otherProjects.length - 1; i >= 0; i--) {
var projectClassList = otherProjects.item(i).classList;
if (projectClassList.contains('showMe')) {
projectClassList.remove('showMe');
projectClassList.add('hideMe');
}
};
You are actually hiding your element and then later showing it again, as an example modify this section to be something like:
otherProjects = doc.getElementsByClassName('projectDetails');
for (var i = otherProjects.length - 1; i >= 0; i--) {
if(otherProjects.item(i).id !== idName){
var projectClassList = otherProjects.item(i).classList;
if (projectClassList.contains('showMe')) {
projectClassList.remove('showMe');
projectClassList.add('hideMe');
}
}
};
In this section you are swapping the visible state of your selected div:
if (!currentProjectClassList.contains('showMe')) {
currentProjectClassList.remove('hideMe');
currentProjectClassList.add('showMe');
} else {
currentProjectClassList.remove('showMe');
currentProjectClassList.add('hideMe');
}
however in the previous section of code because your selected element also has the class projectDetails it gets its showMe removed and hideMe added. So when it gets to section of code above this if(!currentProjectClassList.contains('showMe')) will always be true.

I would use a single class to toggle visibility. It is a lot more manageable. Also I would link click element with the toggled element via an attribute of some kind (instead of using a switch statement in javascript).
EventUtil.addHandler(portfolio, 'click', function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
var divId = target.getAttribute('href');
if (divId) {
event.preventDefault();
Array
.from(document.querySelectorAll('.projectDetails:not(.hideMe)'))
.forEach(function(a) {
a.classList.add('hideMe')
});
document.querySelector(divId).classList.remove('hideMe')
}
});
// Cross-browser event handler
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
getEvent: function(event) {
return event ? event : window.event;
},
getTarget: function(event) {
return event.target || event.srcElement;
},
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
},
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}
};
var portfolio = document.getElementById('portfolio');
EventUtil.addHandler(portfolio, 'click', function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
var divId = target.getAttribute('href');
if (divId) {
event.preventDefault();
Array
.from(document.querySelectorAll('.projectDetails:not(.hideMe)'))
.forEach(function(a) {
a.classList.add('hideMe')
});
document.querySelector(divId).classList.remove('hideMe')
}
});
.projectDetails {
display: block;
}
.projectDetails.hideMe {
display: none;
}
<body>
<div class="container">
<section id="portfolio">
<div class="row">
<div class="col-sm-4">
Section 1
</div>
<div class="col-sm-4">
Section 2
</div>
<div class="col-sm-4">
Section 3
</div>
</div>
<div class="row">
<div id="kkDetails" class="hideMe projectDetails">
<p>Text</p>
</div>
<div id="arthDetails" class="hideMe projectDetails">
<p>Text 2</p>
</div>
<div id="bobyPinzDetails" class="hideMe projectDetails">
<p>Text 3</p>
</div>
</div>
</section>
</body>

Related

How to click one id from a list of ids?

I have a list of ids, when one of them is clicked I want to give it the attribute .className="open.
So far what I've done is to put all ids in a list and try to loop through them.
const memberB = document.querySelectorAll('#memberA, #memberAA, #memberAAA ');
for (var i = 0; i < memberB.length; i++) {
memberB[i].onclick = function(){
alert(memberB[i])
if(memberB[i].className=="open"){
memberB[i].className="";
}
else{
memberB[i].className="open";
}
}
What did I do wrong, I try to alert to see if I get the element that i clicked, all i get is 'undefined'.
you can use forEach to loop the NodeList which use querySelectorAll method, and use addEventListener to watch click event happen on all the elements you selected. Finally, use Element.classList.toggle method to toggle the class open or close
there is an example of toggle its background color after click
const members = document.querySelectorAll('.member');
members.forEach(member => {
member.addEventListener('click', e => {
e.target.classList.toggle('hight-light');
});
});
.member {
background-color: gray;
}
.hight-light {
background-color: green;
}
<div class="container">
<div class="member">1</div>
<div class="member hight-light">2</div>
<div class="member">3</div>
<div class="member">4</div>
</div>
I have a code snippet I like to keep around to do these kind of things in a single event listener
window.addEvent = (event_type, target, callback) => {
document.addEventListener(event_type, function (event) {
// If the event doesn't have a target
// Or the target doesn't look like a DOM element (no matches method
// Bail from the listener
if (event.target && typeof (event.target.matches) === 'function') {
if (!event.target.matches(target)) {
// If the element triggering the event is contained in the selector
// Copy the event and trigger it on the right target (keep original in case)
if (event.target.closest(target)) {
const new_event = new CustomEvent(event.type, event);
new_event.data = { originalTarget: event.target };
event.target.closest(target).dispatchEvent(new_event);
}
} else {
callback(event);
}
}
});
};
then in your case I'd do this
window.addEvent('click', '#memberA,#memberAA,#memberAAA', (event) => {
event.target.classList.toggle('open');
});
The script runs befor the DOM elements load.
You can put the script as a function inside an $(document).ready such that it runs after all the elements have been loaded.
$(document).ready(
function () {
const memberB = document.querySelectorAll('#memberA, #memberAA, #memberAAA ');
for (let i = 0; i < memberB.length; i++) {
memberB[i].onclick = function () {
//alert(memberB[i])
if (memberB[i].className === "open") {
memberB[i].className = "";
} else {
memberB[i].className = "open";
}
alert(memberB[i].className)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="memberA">A</button>
<button id="memberAA">AA</button>
<button id="memberAAA">AAA</button>
Let me know if this works!

How to display hidden div after mouse out or hover

Hi guys can someone help me here I want to make a hidden div being displayed after I trigger the event to display and I remove the mouse on that div here is my code
<div id='MainContainer'>
<div id='btn-img' onmouseover='DisplayHidden()'>content 1</div>
<div id='container2'>content 2</div>
</div>
function DisplayHidden()
{
$('#container2').show();
}
is it possible?
I preferred this way because if you want to add more attributes and comparisons parameters you may add it easily and attribute binding is dynamical.
$(document).ready(function(){
$("#MainContainer > div").on("click",function(e){
if(false === !!$(this).attr('data-click')){
$(this).attr("data-click", true);
alert('No');
}else{
alert('Clicking on same div');
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='MainContainer'>
<div id='container1'>content 1</div>
<div id='container2'>content 2</div>
</div>
Here is what you could do, using pure javascript.
Bind the click event on the container element and use event.target attribute to check the previous click element and take appropriate action.
Event.target documentation on MDN
document.addEventListener("DOMContentLoaded", function() {
var prevElement = null;
document.querySelector("#MainContainer").addEventListener("click", function(event) {
if (prevElement === event.target) {
console.log("Yes")
} else {
console.log("No");
}
prevElement = event.target;
});
});
<div id='MainContainer'>
<div id='container1'>content 1</div>
<div id='container2'>content 2</div>
</div>
var lastClick = null;
$('div#MainContainer div').click(function() {
var clickedId = $(this).attr('id');
if (clickedId == lastClick) {
alert('Clicked the same div');
}
else {
alert('Clicked on a different div');
lastClick = clickedId;
}
});
Here a simple solution with plain javascript:
var g_lastTarget = null
var g_handleClick = function(e) {
var target = e.currentTarget
if (g_lastTarget === target) {
alert('You clicked the container twice. Container ID = ' + target.id)
}
g_lastTarget = target
}
var c1 = document.getElementById('container1')
var c2 = document.getElementById('container2')
c1.addEventListener('click', g_handleClick)
c2.addEventListener('click', g_handleClick)
Create a common class & use querySelectorAll to select the desirable elements.
Then loop through it attach eventListener method to it.Create a variable to store the id of the currently clicked element. On subsequent click check if the variable value and id is same. If it is same then throw an alert.
var getElements = document.querySelectorAll(".elem");
var clickedElem = "";
getElements.forEach(function(item) {
item.addEventListener('click', function() {
if (item.id === clickedElem) {
alert('Clicking on same div')
} else {
clickedElem = item.id
}
})
})
<div id='MainContainer'>
<div id='container1' class="elem">content 1</div>
<div id='container2' class="elem">content 2</div>
</div>

Check whether a div or one of its children were clicked

I have a div as follows
<div class="parent">
<!--several child divs now-->
</div>
Now, I have registered a click handler on body using AngularJS as follows:
HTML:
<body ng-click="registerClick($event)">
</body>
Controller:
$scope.registerClick(e) {
//Here check if the parent div or one of its children were clicked
}
How, can use $event in my handler to determine if the div with class 'parent' or one of its children were clicked?
Change it to this:
$scope.registerClick(e) {
if (e.target.classList.contains('parent')){
// The .parent div is clicked
} else if (e.target.parentNode.classList.contains('parent')){
// Some child of the .parent div is clicked
} else {
var elem = e.target;
while(elem.tagName != 'body' || !elem.classList.contains('parent')){
elem = elem.parentNode;
}
if (elem.classList.contains('parent')){
console.log('DIV .parent')
} else {
console.log('Body tag reached. No .parent element found');
}
}
}
e.target is the clicked element. Use it to determine which element was clicked. This is a clean JavaScript solution. You wont even need the $scope.registerClick(e) { part if can attach the event like so:
someDiv.onclick = function(){/* Same code as above. */}
if you use the latter approach, 'this' points to the div, so you can that the validations a little bit.
You can do something like
var app = angular.module('my-app', [], function() {})
app.controller('AppController', function($scope) {
$scope.registerClick = function($event) {
//if has jQuery
if ($($event.target).closest('.parent').length) {
console.log('clicked parent');
$scope.jQuery = true;
} else {
$scope.jQuery = false;
}
var isParent = false;
if (angular.isFunction($event.target.closest)) {
isParent = !!$event.target.closest('.parent');
} else {
var tmp = $event.target;
do {
isParent = tmp.classList.contains('parent');
tmp = tmp.parentNode;
} while (tmp && tmp.classList && !isParent);
}
$scope.native = isParent;
};
})
.parent {
border: 1px solid grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="my-app">
<div ng-controller="AppController" ng-click="registerClick($event)">
<div>outside</div>
<div class="parent">
parent
<div>div</div>
<div>div</div>
</div>
<div>
jQuery: {{jQuery}}
</div>
<div>
native: {{native}}
</div>
</div>
</div>

Removing attributes of an element on clicking outside with Vanilla JS

How can I remove an attribute of an element on click outside or on another div of same type? Here's my code:
HTML:
<div id="container">
<div data-something></div>
<div data-something></div>
</div>
JavaScript:
var elements = document.querySelectorAll("[data-something]");
Array.prototype.forEach.call(elements, function(element) {
// Adding
element.onclick = function() {
this.setAttribute("data-adding", "");
};
// Removing -- Example
element.onclickoutside = function() {
this.removeAttribute("data-adding");
};
});
I would probably use a click handler on the document, and then remove the attribute from any element that had it that wasn't in the bubbling path.
document.addEventListener("click", function(e) {
Array.prototype.forEach.call(document.querySelectorAll("*[data-adding][data-something]"), function(element) {
var node, found = false;
for (node = e.target; !found && node; node = node.parentNode) {
if (node === element) {
found = true;
}
}
if (!found) {
element.removeAttribute("data-adding");
}
});
}, false);
...or something along those lines.
Live Example:
document.addEventListener("click", function(e) {
Array.prototype.forEach.call(document.querySelectorAll("*[data-adding]"), function(element) {
var node, found = false;
for (node = e.target; !found && node; node = node.parentNode) {
if (node === element) {
found = true;
}
}
if (!found) {
element.removeAttribute("data-adding");
}
});
}, false);
*[data-adding] {
color: red;
}
<div data-adding data-something>One</div>
<div data-adding data-something>Two</div>
You can use Node.contains() inside a global click event handler to check if a click is outside an element, and handle the event appropriately:
box = document.getElementById('box');
lastEvent = document.getElementById('event');
box.addEventListener('click', function(event) {
// click inside box
// (do stuff here...)
lastEvent.textContent = 'Inside';
});
window.addEventListener('click', function(event) {
if (!box.contains(event.target)) {
// click outside box
// (do stuff here...)
lastEvent.textContent = 'Outside';
}
});
#box {
width: 200px;
height: 50px;
background-color: #ffaaaa;
}
<div id="box">Click inside or outside me</div>
<div>Last event: <span id="event">(none)</span>
</div>

transforming jquery to java script

I have this script made with jQuery which I am using to show / hide divs on my page.
I really need it to be made purely in JavaScript and I have no idea how to do this.
Could anyone help me ???
I think I need a converter or something . . .
$("#optiuni").children().click(function(){
$("#" + $(this).attr('name')).show().siblings().hide();
/*Gives the link-activ class to the link that i clicked an link-inactive to all others*/
$(this).attr('class','link-activ').siblings().attr('class','link-neactiv');
});
/*this makes shure that the first option from my list is active incarcarea paginii*/
$("#optiuni li.prima").children().click();
Sample markup:
<div id="lista">
<ul id="optiuni">
<li id="titlu-lista-p"> <p class="listname-t">Past Events </p></li>
<li name="opt-1" class="prima"><p class="listdata">28.02.2011</p><p class="listname">TABU Oscar Party</p> </li>
<li name="opt-2" ><p class="listdata">24.03.2011</p><p class="listname">Cheese & Wine</p></li>
<li name="opt-8"><p class="listdata">08.04.2011</p><p class="listname">George Baicea</p></li>
</ul>
</div>
<div class="centru">
<div id="continut" >
<div id="opt-2" class="galerie" style="background-color: black;">
<iframe id="gal" src="cheese/index.html"></iframe>
</div>
<div id="opt-1" class="galerie" style="background-color: black;">
<iframe src="tabu/index.html"></iframe>
</div>
<div id="opt-8" class="galerie" style="background-color: blue;">
<iframe src="no-ev/index.html"></iframe>
</div>
</div>
</div>
Here's an example of how you could do this based on the markup you linked to in your comment, as there are some assumptions you could make based on the jQuery version which don't hold when you see the markup.
jsFiddle with a live example.
// IE sucks
function addEvent(el, name, handler) {
if (el.addEventListener) {
el.addEventListener(name, handler, false);
} else if (el.attachEvent) {
// Make sure "this" references the element we're adding the event handler to
el.attachEvent('on' + name, function() { handler.call(el, window.event); });
}
}
function eachElementSibling(el, func) {
var childNodes = el.parentNode.childNodes;
for (var i = 0, sibling; sibling = childNodes[i]; i++) {
if (sibling.nodeType !== 1 || sibling === el) {
continue;
}
func(sibling);
}
}
function activateLink() {
var elToShow = document.getElementById(this.getAttribute('name'));
elToShow.style.display = '';
eachElementSibling(elToShow, function(s) { s.style.display = 'none'; });
this.className = 'link-active';
eachElementSibling(this, function(s) {
if (s.getAttribute('name')) { s.className = 'link-neactiv'; }
});
}
var items = document.getElementById('optiuni').getElementsByTagName('li');
var initialItem = null;
for (var i = 0, item; item = items[i]; i++) {
// Need to filter, as non-link items are also present in the list
if (item.getAttribute('name')) {
addEvent(item, 'click', activateLink);
if (item.className === 'prima') {
initialItem= item;
}
}
}
if (initialItem) {
activateLink.call(initialItem)
}

Categories