I would like to add a click event in plain JavaScript (without using jQuery) to an element like this, so I don't have an id but a class:
Yummy
If you don't have an id and don't have any selector library and you want it to work in older browsers, then it takes a bit more work. If you can put an id on it, it's quite simple. If not, it takes more code:
var links = document.getElementsByClassName("MyClass");
links[0].onclick = function() {
// put your click handling code here
// return(false) if you don't want default click behavior for the link
}
Since getElementsByClassName is not universally available in older browsers, you would need a shim to implement it when not present. Or, you could get all the links in your document with:
var links = document.getElementsByTagName("a");
and then cycle through that list until you find the one you want (perhaps checking the class name).
If you can put an ID on the link:
<a href="http://braza.com/share" id="specialLink" class="MyClass" >Yummy</a>
Then, it just takes this code:
document.getElementById("specialLink").onclick = function() {
// add code here
}
If you're going to do this regularly, the adding an event listener is a little more extensible than using the onclick property, but if you don't have any framework, then you need a function for adding an event listener that handles older versions of IE.
There can be several ways of doing this.
One is you add the click event right in the anchor
as: <a href='' onclick='yourFunct()'> Yummy </a>
The other way can be using document.getElementsByTagName('a') you can get reference to all the href's as array then you can chose that particular href and add click event to it.
like: document.getElementsByTagName('a')[0].click = function(){ }
here 0 is just symbolic if u know the exact place in array you can give that index.
The third way can be you can write a custom. document.getElementsByClassName function in javascript and use it similiarly. You can find a number of implementations of getElementsByClassName by searching google.
look at http://robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/ one of the implementation.
You simple use like below
<a href="http://braza.com/share" class="MyClass" onclick='return somefunction()'>Yummy</a>
<script>
function somefunction()
{
// do your stuff.
// return true, if you want to open the link, or false to cancel
return true;
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Untitled</title>
<style type="text/css">
td { border: 1px solid #ccc; }
.findMe { color: gold; }
.youFoundMe { color: green; }
</style>
<script type="text/javascript"><!--
var aryClassElements = new Array();
function doSomething() {
aryClassElements.length = 0;
getElementsByClassName( 'findMe', document.body );
for ( var i = 0; i < aryClassElements.length; i++ ) {
aryClassElements[i].className = 'youFoundMe';
}
}
function getElementsByClassName( strClassName, obj ) {
if ( obj.className == strClassName ) {
aryClassElements[aryClassElements.length] = obj;
}
for ( var i = 0; i < obj.childNodes.length; i++ )
getElementsByClassName( strClassName, obj.childNodes[i] );
}
//--></script>
</head>
<body onload="doSomething();">
<h1>Heading 1</h1>
<div>
This code is inside my div.
<span>This code is inside a span inside the div. Link inside the span inside the div.</span>
Link inside the div.
</div>
<p>
<h2 class="findMe">My Paragraph's Heading 2</h2>
<table>
<tr>
<td class="findMe">My first cell.</td>
<td>My second cell. Link inside the cell inside the row inside the table.</td>
</tr>
</table>
</p>
</body>
</html>`
Related
I have an image (SVG) of a human body. I would like to use JavaScript so that when I click a particular area (say, the lower leg) then all of the elements with the class "lower-leg" (even if not clicked) have their color changed -- this makes it much easier for the user.
Here is the JavaScript I currently have:
function changeclassstyle() {
var c = document.getElementsByClassName("lower-leg");
for (var i=0; i<c.length; i++) {
c[i].style.fill = "red";
}
}
The problem with this code is that it is only generalized for "lower-leg". I may have over a dozen classes I would like this to work for and don't think it is efficient to write 12 functions with the only change being the class name. Is there a way to grab what class was selected and then input that in the function?
--
Additionally, I would love to figure out how, once that section of the body is selected, I can store the class name. I would, in the end, want to store the selection, along with other inputted information in a database. But, this may be for a future question unless someone can help!
Here's how I would do it (tested on a couple of div's).
What we're doing is passing the event object to the event handler (your changeclassstyle() function). It then uses the class of the clicked-on item (the event target's class) and changes everything else on that page with that same class name to use your new desired CSS style.
function changeclassstyle(e) {
// Get all items that have the same class as the item that was clicked
var limbs = document.getElementsByClassName(e.target.className); // for div's and the like
// var limbs = document.getElementsByClassName(e.target.className.baseVal); // turns out this is needed for SVG items
// "limbs" is an HTMLCollection, not an array, so functions like .foreach won't work; C-style for-loops or modern for/let/of loops are better
for (let item of limbs) {
item.style.backgroundColor = 'red';
// item.style.fill = 'red'; // This is probably what you need for your SVG items
}
// You could still use your C-style for loop if needed/wanted
/*
for (var i=0; i<limbs.length; i++) {
limbs[i].style.fill = "red";
}
*/
}
The onchange call looks like this (using my div as the example):
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
The whole example with simple div's.
<html>
<head><title>stuff</title></head>
<body>
<script type="text/javascript">
function changeclassstyle(e) {
// For debugging. You may want to expand 'e' here in your browser's debug tools if you're not seeing the values you need/want
console.log(e)
var limbs = document.getElementsByClassName(e.target.className.baseVal);
for (let item of limbs) {
item.style.backgroundColor = 'red';
}
}
</script>
<style type="text/css">
div {
height: 100px;
width: 100px;
background-color: 'white';
border: 1px solid black;
}
</style>
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
</body>
</html>
You can use parameters in function where you pass class and color like below
function changeStyle(cls,clr) {
let elems = document.getElementsByClassName(cls);
if(!elems) return;
for (let elem of elems) {
elem.style.color = clr;
}
}
As per the iteration of many classes like i said you can store classes in array and iterate each of them.
let classes = ['one','two','three','four'];
classes.forEach(function (cls) {
changeStyle(cls,"red");
});
You can play with fiddle here if you want to test/experiment: https://jsfiddle.net/thrL5uqw/8/
Note: Change style property as you wish, For now i have used color for demo
I'm a bit late to the party, but here's my take on the problem.
Like the others told you, you'll need to use an additional parameter to your function to specify the class you want to modify your elements (or try to figure out the class from the clicked element), therefore you should have something like that:
/**
* This function will handle the click event on one of the part of the SVG.
* #param {string} lClass This the class of the element to modify
*/
function handleClick(lClass) {
for (let e of document.getElementsByClassName(lClass)) {
// Here you can do all the changes you need on the SVG element.
e.style.fill = "red";
}
}
And when it comes to the event binding, you could do like the other suggested and add the onclick event binding propery on the HTML Element, or you could bind it in you JS with the addEventListener function (that way you don't have to repeat the onclick property on each of your SVG elements).
// For each element of all the listed class, bind the "click" event to the handleClick function
const listenClass = [/*List of your classes*/];
for (let l of listenClass) {
for (let e of document.getElementsByClassName(l)) {
e.addEventListener('click', handleClick.bind(this, l));
}
}
Demo: https://plnkr.co/edit/gay2yBaVi5QD868fsTa6?p=preview
I hope it helped.
I am trying to write a tutorial for my students, in the form of a webpage with hidden "spoilers" that the student can unhide, presumably after thinking about the answer. So, long story short, the behavior I am looking for is:
in the beginning, the text appears with a lot of hidden words;
when a piece of text is clicked, it appears, and stays uncovered afterwards;
this should work with minimal overhead (not forcing me to install a complex framework) and on all my students' machines, even if the browser is outdated, even if jquery is not installed.
I searched for off the shelf solutions, but all those I checked were either too complicated or not doing exactly what I wanted. So I decided to do my own.
What I have so far is this:
<HTML>
<STYLE>
span.spoil {background-color: black;}
span.spoiled {background-color: white;}
</STYLE>
<HEAD>
<TITLE>SPOIL</TITLE>
<META http-equiv="Content-Type" content="text/html;charset=UTF-8">
<!--LINK rel="Stylesheet" type="text/css" href=".css"-->
</HEAD>
<BODY>
This is a text with <span class="spoil" onclick="showspoil(this)">spoil data</span>.
<br>
<span class="spoil" onclick="showspoil(this)">Unspoil me.</span>
<br>
<span class="spoil" onclick="showspoil(this)">And me.</span>
<script>
function showspoil(e) {
e.className="spoiled";
}
// var classname = document.getElementsByClassName("spoil");
// for (var i = 0; i < classname.length; i++) {
// classname[i].addEventListener('click', showspoil(WHATEXACTLY?), false);
// }
</script>
</BODY>
</HTML>
It does the job, except that I find it annoying to have to write explicitly the "onclick..." for each element. So I tried adding an event listener to each member of the class, by imitating similar resources found on the web: unfortunately, this part (the commented code above) does not work. In particular, I do not see which parameter I should pass to the function to transmit "the element itself".
Can anyone help? If I may play it lazy, I am more looking for an answer to this specific query than for pointers to a series of courses I should take: I admit it, I have not been doing html for a loooooong time, and I am sure I would need a lot of readings to be efficient again: simply, I do not have the time for the moment, and I do not really need it: I just need to solve this issue to set up a working solution.
Problem here is you are calling the method and assigning what it returns to be bound as the event listener
classname[i].addEventListener('click', showspoil(WHATEXACTLY?), false);
You can either use a closure or call the element directly.
classname[i].addEventListener('click', function () { showspoil(this); }, false);
or
classname[i].addEventListener('click', showspoil, false);
If you call it directly, you would need to change the function to
function showspoil(e) {
this.className="spoiled";
}
Another option would be to not bind click on every element, just use event delegation.
function showspoil(e) {
e.className="spoiled";
}
document.addEventListener("click", function (e) { //list for clcik on body
var clicked = e.target; //get what was clicked on
if (e.target.classList.contains("spoil")) { //see if it is an element with the class
e.target.classList.add("spoiled"); //if it is, add new class
}
});
.spoil { color: red }
.spoiled { color: green }
This is a text with <span class="spoil">spoil data</span>.
<br>
<span class="spoil">Unspoil me.</span>
<br>
<span class="spoil">And me.</span>
function unspoil() {
this.className = "spoiled"; // "this" is the clicked object
}
window.onload = function() {
var spoilers = document.querySelectorAll(".spoil"); // get all with class spoil
for (var i = 0; i < spoilers.length; i++) {
spoilers[i].onclick = unspoil;
}
}
span.spoil {
background-color: black;
}
span.spoiled {
background-color: white;
}
This is a text with <span class="spoil">spoil data</span>.
<br>
<span class="spoil">Unspoil me.</span>
<br>
<span class="spoil">And me.</span>
An additional approach could be to add the click-listener to the document and evaluate the event target:
document.addEventListener("click", function(e){
if (e.target.className == "spoil"){
e.target.className = "spoiled";
}
});
That way
you only need one event listener in the whole page
you can also append other elements dynamically with that class without the need for a new event handler
This should work, because the event's target is always the actual element being clicked. If you have sub-elements in your "spoil" items, you may need to traverse up the parent chain. But anyway I think this is the least resource-wasting way.
var spoilers = document.getElementsByClassName('spoil');
for(i=0;i<spoilers.length;i++){
spoilers[i].addEventListener('click',function(){
this.className = "spoiled";
});
}
I have an AgentClass with the method this.move. It's working with static objects but when I create new HTML Objects via .append(), I can't use them with my this.move method.
All the new objects have an ID and I want to animate them with the move method.
I often read "live, on, ..." but they all need an event... I don't have such an event on them. They move directly. I tried something like that:
$('.agents').on("load", Agent.move());
But that isn't working... Any ideas?
Codesinppet:
var Agent = function(agentType, xTarget, yTarget) {
...
this.move = function() {
var id = this.agentId;
$('.agent#'+id).animate({
left:"200px"
}, 1000);
}
}
And I append them after this like this:
for (deployed = 0; deployed <= agents; deployed++) {
$('.agents').append('<div class="agent" id="'+deployed+'"></div>');
}
It would be awesome if someone could help me!?
You can use .clone(true)
A Boolean indicating whether event handlers and data should be copied along with the elements. The default value is false.
var agents = 6;
for (deployed = 0; deployed <= agents; deployed++) {
$element = $('<div class="agent" id="'+deployed+'"></div>').clone(true);
$('.agents').append($element);
}
.agent {
height:50px;
width:50px;
background-color:yellow;
margin-bottom:10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>Agent</title>
</head>
<body>
<div class="agents">
</div>
</body>
</html>
But for maximum optimization event is better to use an event handler "on" to monitor the items that will be added after reloading the DOM .
This allocates less memory
I have a table with four rows, each one with an "id", and inside each one link with a text.
I want to change the innerHTML of the clicked link with the next one link innerHTML.
So if I have this:
ONE
TWO
THREE
FOUR
and I click on TWO for example, the result must be:
ONE
THREE
TWO
FOUR
As follows my code, which already change the order of the two first links, but it does the same if I click another link.
<html>
<head>
<script type="text/javascript">
function change()
{
var link = document.getElementsByTagName("a");
var i = 0;
var aux = link[i].innerHTML;
link[i].innerHTML = link[i+1].innerHTML;
link[i+1].innerHTML = aux;
}
</script>
</head>
<body>
<table border="1">
<tr id="1"><td>ONE</td></tr>
<tr id="2"><td>TWO</td></tr>
<tr id="3"><td>THREE</td></tr>
<tr id="4"><td>FOUR</td></tr>
</table>
</body>
</html>
I've been working on this all day and I can't see what else can I do. I'm starting with both Java and Javascript, so the use of arrays and the DOM and Javascript functions is new to me.
How does the code know which link was clicked? If you don't tell it, it can't deduce it magically.
First off, remove all those id attributes. They serve no purpose here and will only lead to confusion.
Next, pass this as the first argument of change: onclick="change(this);" and function change(link) {...}.
Now, rewrite your change function to find the right link to change link with, and do the swap as you are now.
Good luck.
You seem to want to do something like:
<style type="text/css">
.shifter {
color: blue;
text-decoration: underline;
cursor: pointer;
}
</style>
<script>
function shiftRows(e) {
var el = e.target || e.srcElement;
var row, tbody;
if (el.tagName.toLowerCase() == 'span' && el.className == 'shifter') {
row = el.parentNode.parentNode;
tbody = row.parentNode;
if (row.rowIndex > 0) {
tbody.insertBefore(row, tbody.rows[row.rowIndex - 1]);
}
}
}
</script>
<table id="t0" onclick="shiftRows(event);">
<tr><td><span class="shifter">0</span>
<tr><td><span class="shifter">1</span>
<tr><td><span class="shifter">2</span>
<tr><td><span class="shifter">3</span>
</table>
I just created script that shows/hides (toggles) block of HTML. There are four buttons that each can toggle its HTML block. When any HTML block is opened, but user has been clicked on other button than that HTML block's associated button... it hides that HTML block and shows new one.
Here is what I have at the moment:
$('.btn_add_event').click( function() {
$('.block_link, .block_photos, .block_videos').hide();
$('.block_event').toggle();
});
$('.btn_add_link').click( function() {
$('.block_event, .block_photos, .block_videos').hide();
$('.block_link').toggle();
});
$('.btn_add_photos').click( function() {
$('.block_event, .block_link, .block_videos').hide();
$('.block_photos').toggle();
});
$('.btn_add_videos').click( function() {
$('.block_event, .block_link, .block_photos').hide();
$('.block_videos').toggle();
});
Any ideas how to reduce code size? Also, this script isn't very flexible. Imagine to add two new buttons and blocks.
like Sam said, I would use a class that all the blocks share, so you never have to alter that code. Secondly, you can try 'traversing' to the closest block, therefore avoiding it's name. That approach is better than hard coding each specific block, but if the html dom tree changes you will need to refactor. Last, but best, you can pass in the class name desired block as a variable to the function. Below is something you can copy paste that is close to what you started with.
$('.myAddButtonClass').click( function() {
$('.mySharedBlockClass').filter(':visible').hide();
//find a good way to 'traverse' to your desired block, or name it specifically for now.
//$(this).closest(".mySharedBlockClass").show() complete guess
$('.specificBlockClass').show();
});
I kept reading this "When any HTML block is opened, but user has been clicked on other button than that HTML block's associated button" thinking that my eyes were failing me when Its just bad English.
If you want to make it more dynamic, what you can do is add a common class keyword. Then
when the click event is raise. You can have it loop though all the classes that have the
keyword and have it hide them all (except the current one that was clicked) and then show the current one by using the 'this' keyword.
you can refer below link,
http://chandreshmaheshwari.wordpress.com/2011/05/24/show-hide-div-content-using-jquery/
call function showSlidingDiv() onclick event and pass your button class dynamically.
This may be useful.
Thanks.
try this
$('input[type=button]').click( function() {
$('div[class^=block]').hide(); // I resumed html block is div
$(this).toggle();
});
Unfortunatly I couldn't test it, but if I can remember right following should work:
function toogleFunc(clickObject, toogleTarget, hideTarget)
{
$(clickObject).click(function()
{
$(hideTarget).hide();
$(toogleTarget).toggle();
});
}
And the call:
toogleFunc(
".btn_add_videos",
".block_videos",
".block_event, .block_link, .block_photos"
);
and so far
Assuming the buttons will only have one class each, something like this ought to work.
var classNames = [ 'btn_add_event', 'block_link', 'block_photos', 'block_videos' ];
var all = '.' + classNames.join(', .'); // generate a jquery format string for selection
$(all).click( function() {
var j = classNames.length;
while(j--){
if( this.className === classNames[j] ){
var others = classNames.splice(j, 1); // should leave all classes but the one on this button
$('.' + others.join(', .')).hide();
$('.' + classNames[j]).toggle();
}
}
}
All the buttons have the same handler. When the handler fires, it checks the sender for one of the classes in the list. If a class is found, it generates a jquery selection string from the remaining classes and hides them, and toggles the one found. You may have to do some checking to make sure the strings are generating correctly.
It depends by how your HTML is structured.
Supposing you've something like this
<div class="area">
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
</div>
...
<div class="sender">
<a class="one"></a>
<a class="two"></a>
<a class="three"></a>
</div>
You have a class shared by the sender and the target.
Your js would be like this:
$('.sender > a').click(function() {
var target = $(this).attr('class');
$('.area > .' + target).show().siblings().hide();
});
You show your real target and hide its siblings, which aren't needed.
If you put the class postfixes in an array, you can easily make this code more dynamic. This code assumed that it doesn't matter in which order toggle or hide are called. If it does matter, you can just remember the right classname inside the (inner) loop, and toggle that class after the loop.
The advantage to this approach is that you can extend the array with an exta class without needing to modifying the rest of the code.
var classes = new Array('videos', 'event', 'link', 'photos');
for (var i = 0; i < classes.length; ++i)
{
$('.btn_add_' + classes[i]).click(
function()
{
for (var j = 0; j < classes.length; ++j)
{
if (this.hasClass('btn_add_' + classes[j]))
{
$('.block_' + classes[j]).toggle();
}
else
{
$('.block_' + classes[j]).hide();
}
}
});
}
You could make this code more elegant by not assigning those elements classes like btn_add_event, but give them two classes: btn_add and event, or even resort to giving them id's. My solution is based on your description of your current html.
Here is what I think is a nice flexible and performant function. It assumes you can contain your links and html blocks in a parent, but otherwise it uses closures to precalculate the elements involved, so a click is super-fast.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" ></script>
<script type="text/javascript">
// Enables show/hide functionality on click.
// The elements within 'container' matching the selector 'blocks' are hidden
// When elements within 'container' matching the selector 'clicker' are clicked
// their attribute with the name 'clickerAttr' is appended to the selector
// 'subject' to identify a target, usually one of the 'blocks'. All blocks
// except the target are hidden. The target is shown.
//
// Change clickerAttr from 'linkTarget' to 'id' if you want XHTML compliance
//
// container: grouping of related elements for which to enable this functionality
// clicker: selector to element type that when clicked triggers the show/hide functionality
// clickerAttr: name of the DOM attribute that will be used to adapt the 'subject' selector
// blocks: selector to the html blocks that will be shown or hidden when the clicker is clicked
// subject: root of the selector to be used to identify the one html block to be shown
//
function initToggle(container,clicker,clickerAttr,blocks,subject) {
$(container).each(
function(idx,instance) {
var containerElement = $(instance);
var containedBlocks = containerElement.find(blocks);
containerElement.find(clicker).each(function(idxC, instanceClicker) {
var tgtE = containerElement.find(subject+instanceClicker.getAttribute(clickerAttr));
var clickerBlocks = containedBlocks.not(tgtE);
$(instanceClicker).click(function(event) {
clickerBlocks.hide();
tgtE.toggle();
});
});
// initially cleared
containedBlocks.hide();
}
);
}
$(function() {
initToggle('.toggle','a.link','linkTarget','div.block','div.');
});
</script>
</head>
<body>
Example HTML block toggle:
<div class="toggle">
a <br />
b <br />
c <br />
<div class="A block"> A </div>
<div class="B block"> B </div>
<div class="C block"> C </div>
</div> <!-- toggle -->
This next one is not enabled, to show scoping.
<div class="toggle2">
a <br />
<div class="A block">A</div>
</div> <!-- toggle2 -->
This next one is enabled, to show use in multiple positions on a page, such as in a portlet library.
<div class="toggle">
a <br />
<div class="A block">A</div>
</div> <!-- toggle (2) -->
</body>
</html>