Javascript onclick event on getElementsByClassName - javascript

I have a svg map and I am putting that into object and I am trying to create all path with id clickable.
For that I am doing this to get svg object :
let a = document.getElementById("biharsvg")
And I am putting that into svg doc like this:
var svgDoc = a.contentDocument;
And now I am getting all the values of certain class using this:
let de = svgDoc.getElementsByClassName("fil0");
I can also get the attribute id value using this:
var i;
for (i = 0; i < de.length; i++) {
var j = de[i].getAttribute("id");
console.log(j);
}
I want to add a click event on each attribute id and get the value when I am doing this:
var i;
for (i = 0; i < de.length; i++) {
var j = de[i].getAttribute("id");
console.log(j);
svgDoc.getElementById(j).onclick = function() {
modal.style.display = "block";
console.log(this.getAttribute("id"));
}
}
This is working fine and I am getting all the values but in jquery I can use this:
$(de).click(function(){
alert(this.getAttribute("id"));
});
Is there any way I can use something like this in javascript without loop. My question is what is the best possible way to make this work in javascript.

The javascript version for jQuery's
$(de).click(function(){
alert(this.getAttribute("id"));
});
would be something like
Array.from(de).forEach( function(el){
el.addEventListener('click', function() {
alert(this.getAttribute("id"));
// or "this.id" should work too
});
});
To be noted, when doing $(de).click(function(){...} with jQuery, it also loops, internally.
And as commented, with arrow functions you could shorten the code even more
Array.from(de).forEach(el => el.addEventListener('click', function () {...}))
var de = document.querySelectorAll('span');
Array.from(de).forEach(el => el.addEventListener('click', function () {
alert(this.id);
}))
span {
display: inline-block;
padding: 20px;
margin: 0 5px;
border: 1px dotted black;
}
span::after {
content: attr(id)
}
<span id="nr1">click </span>
<span id="nr2">click </span>
<span id="nr3">click </span>
Updated based on a comment.
The main difference between your existing loop and the above is, the above is more efficient, with a cleaner/shorter code.
In your original loop
var i;
for (i = 0; i < de.length; i++) {
var j = de[i].getAttribute("id");
svgDoc.getElementById(j).onclick = function() {
modal.style.display = "block";
console.log(this.getAttribute("id"));
}
}
you iterate through the element array de, get its id and then make a new call using getElementById to get the element you already have.
With the kept syntax/logic, your existing code could been simplified to something like this
for (var i = 0; i < de.length; i++) {
de.onclick = function() {
modal.style.display = "block";
console.log(this.getAttribute("id"));
}
}

I just want to show an alternative way, pointed out by CBroe, where a click on the document is checked for its event target:
let de = Array.from(mylist.getElementsByClassName("fil0"));
document.addEventListener('click', function(e) {
const el = e.target;
if (de.indexOf(el) < 0) return false;
alert(el.innerHTML);
});
<ul id="mylist">
<li>one</li>
<li class="fil0">two*</li>
<li class="fil0">three*</li>
</ul>
<p>* has click event assigned indirectly</p>
This has the additional benefit that it only uses a single handler function, and if the indexOf() condition is changed to something like classList.contains(), it will even work for elements that don't exist yet.

I find for..of to be the most convenient and readable syntax:
for (const element of svgDoc.getElementsByClassName("fil0")) {
console.log(element.id);
}

Related

Binding an event listener to multiple elements with the same class

I'm trying to apply the onclick event with JavaScript to the following elements:
<div class="abc">first</div>
<div class="abc">second</div>
<div class="abc">third</div>
If I click on the first element (with index [0]) then this works, but I
need this event applicable for all classes:
document.getElementsByClassName('abc')[0].onclick="function(){fun1();}";
function fun1(){
document.getElementsByClassName('abc').style.color="red";
}
.onclick does not expect to receive a string, and in fact you don't need an extra function at all.
However, to assign it to each element, use a loop, like I'm sure you must have learned about in a beginner tutorial.
var els = document.getElementsByClassName('abc');
for (var i = 0; i < els.length; i++) {
els[i].onclick = fun1;
}
function fun1() {
this.style.color = "red";
}
<div class="abc">first</div>
<div class="abc">second</div>
<div class="abc">third</div>
To expand on the solution provided by #rock star I added two small additions to the function. First it is better to add / reemove a class (with an associated style rule) to an element than directly applying the stylerule to the element.
Secondly - on the click event - this will now remove the red class (and therefore style) from the previously selected element and add it to the new element. This will allow only one element to be red at a time (in the original solution any element that was clicked would become red).
var els = document.getElementsByClassName('abc');
for (var i = 0; i < els.length; i++) {
els[i].onclick = fun1;
}
function fun1() {
var oldLink = document.getElementsByClassName('red')[0];
if(oldLink) {oldLink.classList.remove('red')};
this.classList.add('red');
}
.red {
color:red;
}
<div class="abc">first</div>
<div class="abc">second</div>
<div class="abc">third</div>
This works:
<body>
<div class="abc">first</div>
<div class="abc">second</div>
<div class="abc">third</div>
<script>
var elements = document.getElementsByClassName('abc');
for(var i = 0, max = elements.length; i < max; i += 1) {
var clickedElement = elements[i];
clickedElement.onclick=function (){
fun1(this);
};
}
function fun1(element){
element.style.color="red";
}
</script>
</body>

Catching className number in javascript

It's easy to change class 'day' with addEventListener if I specify it with day[2], day[3] etc.
I don't really want to write all that code for each of them, how could I catch the class' order number "day[?]" when it's clicked, so I could use it in changeDate().
Parts of current code:
var day = document.getElementsByClassName("day");
day[2].addEventListener("click", changeDate);
function changeDate() {
console.log("hit");
}
<li class="day">1</li>
<li class="day">2</li>
<li class="day">3</li>
In the changeData() function, you are able to access to this. It's the associated <li> (which were clicked), so use this.innerHTML to get the number of the day.
You can use the following code using standard javascript to find and attach click event handlers to all .day HTML elements.
<body>
<li class="day">1</li>
<li class="day">2</li>
<li class="day">3</li>
...
</body>
<script>
var dayArray = [];
window.onload = function(){
dayArray = document.getElementsByClassName("day");
for (var i = 0; i < dayArray.length; i++) {
dayArray[i].addEventListener('click', changeDate, false);
}
};
function changeDate(evt){
console.log(this); // Here 'this' refers to the clicked HTML element
}
</script>
Hope this helps.
Get all of the classes and loop through them to add listeners, like this:
var days = document.getElementsByClassName('day');
for(var i = 0; i < days.length; i++){
days[i].addEventListener('click', changeDate);
}
EDIT: sorry, missed the last line: Your change date function can then include the following:
function changeDate(){
var day = this.textContent;
};
Now the day variable in the text inside the element that was clicked.
Addition to #fauxserious answer you could try this:
var days = document.getElementsByClassName('day');
for(var i = 0; i < days.length; i++){
days[i].addEventListener('click', changeDate);
}
function changeDate(){
console.log('Clicked day ' + this.innerHTML);
}

Javascript - Toggle Multiple Classes onclick

I am trying to toggle multiple classes onclick using vanilla Javascript. What i am trying to do is when a btn is clicked two classes to toggle with another two classes. I have 5 classes in total which are: .menu_btn , .main_nav, .btn_active, .container, .container_active. When i press the .menu_btn i would like the classes .main_nav to toggle with .btn_active and at the same time i would like to have the .container to toggle with .container_active. The class .container is the only one that has 5 elements of that class, the others are single. I have done this using jQuery but i would like to know the way using vanilla Javascript. Hopefully someone can help.
One thing to point out is when i console.log the .btn_active and .container_active i get back [ ] an empty array. Those 2 css classes are not assigned to any element of my project. They are existing only in the css and their purpose is for toggle.
Thanks
jQuery Code:
$(function(){
$(".menu_btn").on("click", function(){
$(".main_nav").toggleClass("btn_active");
$(".container").toggleClass("container_active");
});
});
Vanilla Javascript Code:
var menuBtn = document.getElementsByClassName("menu_btn");
var mainNav = document.getElementsByClassName("main_nav");
var btnActive = document.getElementsByClassName("btn_active");
var container = document.getElementsByClassName("container");
var containerActive = document.getElementsByClassName("container_active");
menuBtn.onclick = function(){
mainNav.classList.toggle(btnActive);
for ( index = 0; index <= container.lenght -1; index++ ){
container[index].classList.toggle(containerActive);
}
};
I have modified your script and created a fiddle so you see how it works: https://jsfiddle.net/eyrpdsc2/
The toggle accepts a string as a parameter, not a Node. So you need to pass 'btn_active' instead of btnActive. Also keep in mind that querySelectorAll returns a NodeList (not an array) so you cannot use forEach.
var menuBtn = document.querySelectorAll(".menu_btn");
var mainNav = document.querySelectorAll(".main_nav");
var container = document.querySelectorAll(".container");
for (var i = 0; i < menuBtn.length; ++i) {
menuBtn[i].addEventListener('click', toggleClasses);
}
function toggleClasses() {
var i = 0;
for (i = 0; i < mainNav.length; ++i) {
mainNav[i].classList.toggle('btn_active');
}
for (i = 0; i < container.length; ++i) {
container[i].classList.toggle('container_active');
}
}

Hide content inside brackets using pure JavaScript

I want to use pure JavaScript to hide all content inside brackets in a document. For example, this:
Sometext [info]
would be replaced with this:
Sometext
With jQuery I can do this with:
<script type="text/javascript">
jQuery(document).ready(function(){
var replaced = jQuery("body").html().replace(/\[.*\]/g,'');
jQuery("body").html(replaced);
});
</script>
The document's DOMContentLoaded event will fire at the same time as the callback you pass to jQuery(document).ready(...).
You can access the body of the page through document.body instead of jQuery("body"), and modify the HTML using the .innerHTML property instead of jQuery's .html() method.
document.addEventListener("DOMContentLoaded", function(event) {
var replaced = document.body.innerHTML.replace(/\[.*\]/g,'');
document.body.innerHTML = replaced;
});
If you use, document.body.innerHTML to replace, it is going to replace everything between [], even valid ones like input names. So I think what you need is to grab all of the textnodes and then run the regex on them. This question looks like it will do the trick.
function recurse(element)
{
if (element.childNodes.length > 0)
for (var i = 0; i < element.childNodes.length; i++)
recurse(element.childNodes[i]);
if (element.nodeType == Node.TEXT_NODE && /\S/.test(element.nodeValue)){
element.nodeValue = element.nodeValue.replace(/\[.*\]/g,'');
}
}
document.addEventListener('DOMContentLoaded', function() {
// This hits the entire document.
// var html = document.getElementsByTagName('html')[0];
// recurse(html);
// This touches only the elements with a class of 'scanME'
var nodes = document.getElementsByClassName('scanME');
for( var i = 0; i < nodes.length; i++) {
recurse(nodes[i]);
}
});
You already have the solution, try "Sometext [info]".replace(/\[.*\]/g,'');
Basically what your doing is this
document.addEventListener('DOMContentLoaded', function() {
var replaced = document.body.innerHTML.replace(/\[.*\]/g,'');
document.body.innerHTML = replaced
});
That would be a silly idea though (speaking for myself)
Make your life easier & your site better by doing something like this
<p> Sometext <span class="tag-variable"> [info] </span> </p>
document.addEventListener('DOMContentLoaded', function(){
var tags = document.getElementsByClassName('tag-variable');
for( var i = 0; i < tags.length; i++) {
var current = tags[i]; // Work with tag here or something
current.parentNode.removeChild( current );
}
});

Accessing DOM elements without id

i have a page around 500 div as below.
<div onclick='test()' class='test>
<ul class='innermenu'>
<li>1</li>
.....
</ul>
</div>
when the test function is called it need to hide the menu (innermenu) who calls that function.
my problems are
uniquely identify the div without using id
How to hide only the particular ul alone.
OK, first the quick fix, though it is not the best way to use JS on your page:
Change the call to this:
<div onclick="test(this);" class="test">
Then, in test, use this:
function test(el){
var uls = el.getElementsByTagName('ul');
for(var i = 0; i < uls.length; i++){
if(uls[i].className == 'innermenu'){
uls[i].style.display = "none";
break;
}
}
}
This will hide just the child ul of the div that is clicked.
A better way
OK, for the longer answer. Either attach the events after the fact using attachEvent and addEventListener or use a library like jQuery to help you out. Here is the raw solution:
Set up your HTML this way (no onclick):
<div class="test">
And then at the very end of your HTML put this:
<script type="text/javascript">
var divs = document.getElementsByTagName('div');
function test(){
var uls = this.getElementsByTagName('ul');
for(var i = 0; i < uls.length; i++){
if(uls[i].className == 'innermenu'){
uls[i].style.display = "none";
break;
}
}
};
for(var i = 0; i < divs.length; i++){
var div = divs[i];
if(div.className !== "test") continue;
if(window.addEventListener){
div.addEventListener( 'click', test, true ); //FF, Webkit, etc
} else if (window.attachEvent) {
div.attachEvent('onclick', test); // IE
} else {
div.onclick = test; // Fallback
}
}
</script>
Now, you don't have JavaScript code in your HTML, and you can get rid of the extra parameter on the test function.
There is a method
document.getElementsByClassName
but it isn't supported in all browsers.
javascript
function test(elem)
{
var childElem = elem.children[0];
childElem.style.display = 'none';
}
<div onclick='test(this)' class='test'>
<ul class='innermenu'>
<li>1</li>
<li>2</li>
</ul>
</div>
If you can use jQuery then you can do something like this
$("div.test").click(function(){
$(this).find("ul.innermenu").hide();
});
If you don't want assign ids, you can try this to hide the div which gets clicked:
<div onclick="hideMe(this);" class='test>
<script>
function hideMe(elem)
{
elem.style.display = 'none';
}
</script>
Try passing "this" as parameter:
<div onclick='test(this)' class='test>
<ul class='innermenu'>
<li>1</li>
.....
</ul>
function test(sender) {
//sender is DOM element that is clicked
alert(sender.id);
}
If getElementsByClassName is not supported by all browsers as mentioned by #rahul, you can iterate through the dom and find it yourself - provided there is only one <ul> with class name "innermenu"
var uls = document.body.getElementsByTagName("ul");
var len = uls.length;
for(var i = 0; i < len; i++)
{
var ul = uls.item(i);
if(ul.getAttribute("class") == "innermenu")
{
ul.style.display = "none";
break;
}
}

Categories

Resources