toggle password/text with javascript only - javascript

I'd like to change the following code to javascript only:
$(document).ready(function() {
$('.fa-eye, .fa-eye-slash').click(function() {
$(this).toggleClass('fa-eye fa-eye-slash');
var input=$(this).parent().find('input');
if(input.attr('type')=='password') {
input.attr('type', 'text');
}else input.attr('type', 'password');
});
});
What is does is when you click in an "eye icon" it changes that icon to "eye-slash icon" and changes the password field within the same div to text, so basically toggle password/text.
Since this is currently the only javascript I'm using, I thought it would be overkill to include jQuery or ZeptoJS only for this and this can probably be done with a few lines of javascript.
Please notice: this needs to be applied to multiple fields, that is why I opted not to use ID.

These are the corrections made to make it work with no jQuery and just relying on vanilla JS and Web API (https://developer.mozilla.org/en-US/):
.addEventListener() to add bubbling event handlers to the elements
DOMContentLoaded event instead of $(document).ready()
.querySelectorAll() and .querySelector() to select elements instead of using the $ function
.classList.toggle() instead of .toggleClass()
event.target instead of $(this)
.getAttribute() and .setAttribute() instead of attr()
.forEach() to iterate over the array of returned elements
document.addEventListener('DOMContentLoaded', ()=>{
document.querySelectorAll('.fa-eye, .fa-eye-slash')
.forEach( el => {
el.addEventListener('click', event =>{
const trigger = event.target;
trigger.classList.toggle('fa-eye');
trigger.classList.toggle('fa-eye-slash');
const input = trigger.parentNode.querySelector('input');
if (input.getAttribute('type') == 'password')
input.setAttribute('type', 'text');
else
input.setAttribute('type', 'password');
});
});
});
i{
cursor: pointer;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<div>
<input type="password">
<i class="fa-solid fa-eye"></i>
</div>
<hr>
<div>
<input type="password">
<i class="fa-solid fa-eye"></i>
</div>

You can do it with normal vanilla JS means, see this snippet:
function load() {
for (let fa of document.querySelectorAll('.fa-eye, .fa-eye-slash')) {
fa.addEventListener('click', function(e) {
e.target.classList.toggle('fa-eye');
e.target.classList.toggle('fa-eye-slash');
let input = e.target.parentNode.querySelectorAll('input');
for (let item of input) {
if (item.type === 'password') item.type = 'text';
else item.type = 'password';
}
});
}
}
window.addEventListener('load', load);
<div>
<input type="password" value="foo">
<input type="test" value="bar">
<div class='fa-eye' style="background-color: green;">CLICK ME</div>
</div>
Note that jQuery is also Javascript, albeit, Javascript is not necessarily jQuery.

Related

How to remove text between <a> with javascript

I am using javascript and jquery to change the text inside of an a tag. I was reading that document.getElementById("yearA").innerHTML = ''; would remove the text but it isn't working. I'm not sure if it's because I am adding text to the a tag then trying to remove it or not. Any help with this would be appreciated. Here is my html
document.getElementById("filter-div").style.visibility = "visible";
document.getElementById("yearA").style.visibility = "visible";
document.getElementById("yearA").innerHTML += 'Remove Link';
console.log('Link added')
function hideYear() {
document.getElementById("yearA").innerHTML = '';
console.log('Link removed')
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="hidden" id="hiddenTag" />
<div id="filter-div" class="filter-div" style="visibility: hidden;">
<a id="yearA" onclick="hideYear()" style="visibility: hidden;"></a>
</div>
Jquery based solution
you may try:
$('#yearA').text("");
I'm not sure why you are throwing jquery into the mix, but here is a full example with hide and show functions
HTML:
<input type="hidden" id="hiddenTag" />
<div id="filter-div" class="filter-div" style="visibility: hidden;">
<a id="yearA" onclick="hideYear(event)"></a>
<div id="showYear" onclick="showYear(event)" style="visibility: hidden;">
show year
</div>
</div>
Javascript:
const year = new Date().getYear();
document.getElementById("filter-div").style.visibility = "visible";
document.getElementById("yearA").innerHTML += "Remove " + year;
function hideYear(evt) {
evt.preventDefault();
evt.stopPropagation();
document.getElementById("showYear").style.visibility = "visible";
document.getElementById("yearA").innerHTML = "";
}
function showYear(evt) {
evt.preventDefault();
evt.stopPropagation();
document.getElementById("showYear").style.visibility = "hidden";
document.getElementById("yearA").innerHTML = "Remove " + year;
}
Maybe you're looking for something like this? Let me know.
function hideYear() {
document.getElementById("yearA").innerHTML = '';
}
<input type="hidden" id="hiddenTag" />
<div id="filter-div" class="filter-div">
<a id="yearA" onclick="hideYear()">test</a>
</div>
Don't make use of innerHTML. That will change the entire html node. If your requirement is just to clear the text within the element, try making use if innerText property. Select the node either via JavaScript or jQuery, update the innerText, that will preserve the href of the anchor tag.
Try making use of innerText.
JavaScript Implementation
function removeText() {
document.getElementById('google').innerText = '';
}
Go To Google
<button onclick="removeText()">Remove Text</button>
jQuery Implementation
function removeText() {
$('#google').text('');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
Go To Google
<button onclick="removeText()">Remove Text</button>

Changing the Style of a HTML-Button within a JavaScript Function

I am trying to change the style class of a button when clicking it but it is not working how it should.
I need the style/icon change inside a JS function because I am doing some more stuff when the buttons gets clicked.
function generate() {
//// Some stuff
document.getElementById('btn1').class = 'play icon fa fa-stop';
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<div class='container20'>
<button class='play icon fa fa-play-circle-o' type='button' onclick='generate()' id="btn1">Button</button>
</div>
class not exist, there is className, so replace it by className
In onclick there is function so, you need to add () in it so, replace generate to generate().
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<div class='container20'>
<button class = 'play icon fa fa-play-circle-o' type = 'button' onclick = 'generate()' id = "btn1">Button</button>
</div>
<div class='container80'>
<script>
function generate() {
//// Some stuff
document.getElementById('btn1').className = 'play icon fa fa-stop';
}
</script>
</div>
Use className and not class
document.getElementById('btn1').className = 'play icon fa-stop';
Try the following:
Below code will add the 3 classes to any existing classes already applied to the button
document.getElementById('btn1').classList.add('play', 'icon', 'fa-stop');
Below code will replace any existing classes already added to the button with play, icon and fa-stop
document.getElementById('btn1').className = 'play icon fa-stop';
Rather than setting className, and having to preserve the play icon parts of the className text, you can use classList to remove and add the necessary classes
function generate() {
const b = document.getElementById('btn1')
b.classList.remove('fa-play-circle-o`);
b.classList.add('fa-stop');
}
Yes, it's more lines, but it's more flexible too. For example you could write a method that takes the old class and the new class and call it from anywhere.
function changeClass(element, old, new) {
element.classList.remove(old);
element.classList.add(new);
}
Also, since you are running in an event handler, you don't have to getElementById('btn1') because the event.target is the button that was clicked.
This (below) attaches an event handler, rather than using an inline onclick=, and I've added background color just so the effect of clicking the button can be seen.
document.getElementById('btn1')
.addEventListener('click', function(e) {
e.target.classList.remove('fa-play-circle-o');
e.target.classList.add('fa-stop');
});
button {
font-weight: bold;
}
button.fa-play-circle-o {
background-color: lightsalmon;
}
button.fa-stop {
background-color: lightgreen;
}
<div class="container20">
<button id="btn1" type="button"
class="play icon fa-play-circle-o">Button</button>
</div>

Trouble with to-do list close button

I have some code that seems to be working, but in a rather odd fashion. When I first refresh the page I have the close button that seems to work fine, but when I make a new to-do list item the close button seems to cease working and I can't pinpoint why.
let addItem = document.getElementById("submitButton");
let userInput = document.getElementById("toDoInput");
let output = document.getElementById("output");
let toDoItem = document.querySelector(".toDoItem");
let close = document.querySelector(".close");
let toDo = document.querySelector(".todo");
/*User clicked the addItem Button
If there is any text inside the text field then add that text to the todo list */
addItem.addEventListener("click", addToDo);
function addToDo(){
var html = `
<ul class="todo">
<li class="toDoItem">
<p>${userInput.value}</p>
<div class="close">X</div>
</li>
</ul>
`;
output.innerHTML += html;
// Resetting input to blank once a submit button has been added.
userInput.value = '';
}
// Figure out how to make closing functionality simple this implementation
// isn't working
close.addEventListener("click", function(e){
console.log("clicked");
let x = e.target.parentElement;
x.style.display = "none";
e.preventDefault();
});
<header>
<input type="text" placeholder="Enter Item Here..." id="toDoInput">
<button id="submitButton">+</button>
</header>
<section id="output">
<ul class="todo">
<li class="toDoItem">
<p>Clean Room!</p>
<div class="close">X</div>
</li>
</ul>
</section>
<script src="todo.js"></script>
I'm also not sure if I'm using best practice as I'm new to web development, so any tips would be thoroughly appreciated as well!
You need a live event handler on your close button(s). This example should help. To offer something more, it's easier and more straight forward to use jQuery for it if you can and don't mind using a JS library.
jQuery example:
$(document).on("click", ".close", function() {
$(this).parent().hide();
});
No need to prevent default behavior since it's a div.
The issue here is that when you re-render the content of the "output" section you lose the event listener bound to the original ".close" element. A few options to work around the issue, have a look at this thread for some examples.
You got pretty close man, and you definitely do not need jQuery.
As you can see below, you don't need to push the <ul> dynamically. It will never change!
<header>
<input type="text" placeholder="Enter Item Here..." id="toDoInput">
<button id="submitButton">+</button>
</header>
<section id="output">
<ul class="todo">
</ul>
</section>
And here is your refactored javascript:
let addItem = document.getElementById("submitButton");
let userInput = document.getElementById("toDoInput");
let output = document.getElementById("output");
let toDoItem = document.querySelector(".toDoItem");
let toDo = document.querySelector(".todo");
/*User clicked the addItem Button
If there is any text inside the text field then add that text to the todo
list */
addItem.addEventListener("click", addToDo);
function addToDo(e){
e.preventDefault();
var html = `<li class="toDoItem">
<p>${userInput.value} </p> <p class="close"
onclick="removeChildElement(this);">X</p>
</li>`;
output.innerHTML += html;
let close = document.querySelector(".close")
// Resetting input to blank once a submit button has been added.
userInput.value = '';
}
// Figure out how to make closing functionality simple this implementation
// isn't working
function removeChildElement(e) {
let x = e.parentElement;
let xParent = x.parentElement;
xParent.removeChild(x);
console.log(xParent);
}
As you can see i made a few changes. Most importantly your close button issue. The function gets the parent on its parent ( ^ 2 ) and then removes its child. Which would be your <li> element!
Enjoy the fiddle: https://jsfiddle.net/fjbyy6uw/35/
Use Event Delegation. Details are commented in Demo. Added a <form> so HTMLFormControlsCollection API can be used, it's simpler, less writing, and I'm lazy.
/* All form controls are referenced by HTMLFormControlsCollection */
var form = document.forms.toDo;
var td = form.elements;
var add = td.add;
var inp = td.input;
var out = td.output;
var toDo = document.querySelector('.toDo');
add.addEventListener("click", addToDo);
/* Limited the dynamically created node to `<li>`. It doesn't make sense to
|| have several `<ul>` having only one `<li>` each.
*/
function addToDo() {
var html = `
<li class="item">
<span>${inp.value}</span>
<b class="close">X</b>
</li>
`;
toDo.innerHTML += html;
}
/* Event Delegation is a way of leveraging event bubbling so
|| that a single ancestor node can be registered to listen for
|| an event (e.currentTarget) and by means event propagation
|| (bubbling) can locate the event origin (node clicked/e.target).
|| In this demo e.currentTarget is output#output and e.target are
|| any b.close. This was possibble by using e.target in conditions
*/
/* removeChild() is used because display:none is not entirely
|| gone. The markup remains just not in the DOM, so it may not
|| look like it's there, under certain conditions a node could be
|| considered present.
*/
out.addEventListener("click", function(e) {
if (e.target !== e.currentTarget) {
if (e.target.className === "close") {
let x = e.target.parentElement
x.parentElement.removeChild(x);
}
}
});
.item {
display: flex;
max-width: 250px;
justify-content: space-between;
}
.item span,
.item b {
display: table-cell;
}
.item b {
cursor: pointer
}
input,
output,
button {
font: inherit
}
<form id='toDo'>
<header>
<input type="text" placeholder="Enter Item Here..." id="input">
<button id="add" type='button'>+</button>
</header>
<output id="output">
<ul class="toDo">
<li class="item">
<span>Clean Room!</span>
<b class="close">X</b>
</li>
</ul>
</output>
</form>

Link <a> tag downloading the default HTML page when condition is not fulfilled

I am facing a weird problem. I have a link tag to download like
<div class="col-md-4 about-right">
<ul>
<h5>Get My Cv</h5>
<li><span class="glyphicon glyphicon-user"><input type="radio"class="rad" id="radio1" name="optradio"></span>Download In PDF</li>
<li><span class="glyphicon glyphicon-user"><input type="radio" class="rad" id="radio2" name="optradio"></span>Download In Word Doc</li>
<li><span class="glyphicon glyphicon-user"><input type="radio" class="rad"id="radio3"name="optradio"></span>Download In HTML</li>
<center>
<a href="#" id="cvLink" download onclick="getCv()">
<button type="button" class="btn btn-info">Download</button></a>
</center>
</ul>
</div>
Which downloads documents using radio button checked validation.I have also 3 radio button. I change the URL link based on which radio button is clicked and download the documents using JavaScript. But the problem is when any of the radio button is unclicked I want to show an alert and make the link to do nothing.
I tried this by using "# , javaScript:void(0)". it shows the alert but also downloads the main HTML file on which I am working on. I just want the link will do nothing but show the alert only.
My code is something like below
<script>
function getCv() {
if(document.getElementById('radio1').checked) {
document.getElementById('cvLink').href = "https://drive.google.com/uc?export=download&id=MZTFCWnRYbnlvclk";
}
else if(document.getElementById('radio2').checked) {
document.getElementById('cvLink').href = "https://drive.google.com/uc?export=download&id=uK6ct7MZ2N6Ni1qQUFyWXM";
}
else if(document.getElementById('radio3').checked) {
document.getElementById('cvLink').href = "https://drive.google.com/uc?export=download&id=0VDenJqUldud2M";
}
else
{
alert('Please Select Any Format To Download!!');
}
return false;
}
</script>
First, before we get to the answer to your question I'd like to take a moment to point out some issues with your HTML:
<div class="col-md-4 about-right">
<ul>
<h5>Get My Cv</h5>
<li><span class="glyphicon glyphicon-user">
<input type="radio"class="rad" id="radio1" name="optradio"></span>Download In PDF
</li>
<li><span class="glyphicon glyphicon-user">
<input type="radio" class="rad" id="radio2" name="optradio"></span>Download In Word Doc</li>
<li><span class="glyphicon glyphicon-user">
<input type="radio" class="rad"id="radio3"name="optradio"></span>Download In HTML</li>
<center>
<a href="#" id="cvLink" download onclick="getCv()">
<button type="button" class="btn btn-info">Download</button>
</a>
</center>
</ul>
</div>
So, the first problem is one that recurs twice, that the only valid direct child element of a <ul> (or an <ol>) is the <li> element. The others you have in there, the <h5> and the <center> (more on that in a moment) are invalid HTML where they're placed here.
You have the option of either removing those elements from the <ul>, as I've done, or you can simply wrap them in a parent <li> so that the DOM structure becomes valid.
Further, the <center> element has been deprecated since HTML 4.1, I think. Regardless of when it was deprecated, however, it remains deprecated and should no longer be used. If you should need to center something in your layout use CSS to style the presentation of the document, HTML should only define the structure.
Also, and I think this is the last issue with your HTML, it's invalid HTML to have an interactive element, such as a <button>, within another interactive element, such as an <a>. In my demo to reproduce your problem I simply discarded the <button> element, since it has no download attribute.
That said, the following JavaScript is my proposed solution, the HTML is also in the snippet along with the JavaScript and CSS:
// a named function to highlight the <input> elements required
// in order to enable the <a> element:
function highlightRequirements(e) {
// caching the element that initiated the events
// here the <a> element:
let clicked = this,
// retrieving the elements that are required to
// be chosen amongst before the <a> can be used:
required = document.querySelectorAll(
// I store, in the <a> element the attribute:
// data-required="input[name=optradio]"
// here we use the HTMLElement.dataset interface
// to retrieve that selector, which is passed as
// the argument to document.querySelectorAll:
clicked.dataset.required
);
// if the event type (the event, 'e', is passed automatically
// from the EventTarget.addEventListener() method) is the
// 'mouseenter' event:
if (e.type === 'mouseenter') {
// if the <a> element has the download attribute set:
if (clicked.download) {
// we remove the event-listener bound to that element
// for both 'mouseenter' and 'mouseleave' events:
this.removeEventListener('mouseenter', highlightRequirements);
this.removeEventListener('mouseleave', highlightRequirements);
// and we iterate over the required elements, using
// Array.prototype.forEach(), and an Arrow function
// expression, to remove the 'highlight' class from
// the parentNode of each required ('req') element:
required.forEach(req => req.parentNode.classList.remove('highlight'));
} else {
// if the <a> element does not have the download property,
// we iterate over the required elements and add the
// 'highlight' class-name, in order to trigger the animation
// defined in the CSS, in order to draw the users' attention:
required.forEach(req => req.parentNode.classList.add('highlight'));
}
// otherwise, if the event was not the 'mouseenter' event (and so
// must be the 'mouseleave' event):
} else {
// we iterate over the required elements, and remove the 'highlight'
// class-name from their parentNodes:
required.forEach(req => req.parentNode.classList.remove('highlight'));
}
}
// a named function, fired by the radio inputs, to
// 'enable' or 'activate' the <a> element:
function linkActivate(e) {
// we use document.querySelector to retrieve the first
// - if any - element matching the supplied selector:
var link = document.querySelector(
// similarly to above, I stored the selector for the
// relevant <a> element in the 'data-link' attribute,
// and retrieve that attribute-value using the
// HTMLElement.dataset interface:
this.dataset.link
);
// setting the download attribute to 'true':
link.download = true;
// retrieving the 'data-downloadfrom'
// attribute-value from the changed
// radio input:
link.href = this.dataset.downloadfrom;
// adding the 'allowed' class to the
// <a> element, to show that interaction
// is now possible:
link.classList.add('allowed');
}
// selecting all the <input> elements with name="optradio":
let radios = document.querySelectorAll('input[name=optradio]'),
// converting that NodeList into an Array, using
// Array.from():
radioArray = Array.from(radios),
// retrieving the <a> element using
link = document.querySelector('#cvLink');
// iterating over the Array of radio-inputs using
// Array.prototype.forEach() and an Arrow function:
radioArray.forEach(
// here we bind the linkActivate() function as the
// event-handler for the 'change' event:
radio => radio.addEventListener('change', linkActivate)
);
// here we bind the highlightRequirements() function as
// the event-handler for the 'mouseenter' and 'mouseleave'
// events for the <a> element:
link.addEventListener('mouseenter', highlightRequirements);
link.addEventListener('mouseleave', highlightRequirements);
function highlightRequirements(e) {
let clicked = this,
required = document.querySelectorAll(clicked.dataset.required);
if (e.type === 'mouseenter') {
if (clicked.download) {
this.removeEventListener('mouseenter', highlightRequirements);
this.removeEventListener('mouseleave', highlightRequirements);
required.forEach(req => req.parentNode.classList.remove('highlight'));
} else {
required.forEach(req => req.parentNode.classList.add('highlight'));
}
} else {
required.forEach(req => req.parentNode.classList.remove('highlight'));
}
}
function linkActivate(e) {
let link = document.querySelector(this.dataset.link);
link.download = true;
link.href = this.dataset.downloadfrom;
link.classList.add('allowed');
}
let radios = document.querySelectorAll('input[name=optradio]'),
radioArray = Array.from(radios),
link = document.querySelector('#cvLink');
radioArray.forEach(
radio => radio.addEventListener('change', linkActivate)
);
link.addEventListener('mouseenter', highlightRequirements);
link.addEventListener('mouseleave', highlightRequirements);
#keyframes highlight {
0% {
background-color: transparent;
}
75% {
background-color: limegreen;
}
100% {
background-color: transparent;
}
}
ul + a {
display: inline-block;
text-align: center;
text-decoration: none;
margin: 0.5em auto;
}
ul + a {
color: #66c;
cursor: no-drop;
border: 2px solid #66c;
padding: 0.2em 0.4em;
border-radius: 0.5em;
opacity: 0.5;
}
ul + a.allowed {
opacity: 1;
cursor: pointer;
}
li span.highlight {
animation: 3s highlight;
}
<div class="col-md-4 about-right">
<ul>
<li>
<span class="glyphicon glyphicon-user">
<input type="radio"class="rad" id="radio1" name="optradio" data-downloadfrom="https://drive.google.com/uc?export=download&id=MZTFCWnRYbnlvclk" data-link="#cvLink" />
</span>Download In PDF</li>
<li>
<span class="glyphicon glyphicon-user">
<input type="radio" class="rad" id="radio2" name="optradio" data-downloadfrom="https://drive.google.com/uc?export=download&id=uK6ct7MZ2N6Ni1qQUFyWXM" data-link="#cvLink" />
</span>Download In Word Doc
</li>
<li>
<span class="glyphicon glyphicon-user">
<input type="radio" class="rad" id="radio3" name="optradio" data-downloadfrom="https://drive.google.com/uc?export=download&id=0VDenJqUldud2M" data-link="#cvLink" />
</span>Download In HTML
</li>
</ul>
Download CV
</div>
JS Fiddle demo.
The above seems to work, though I've not verified it properly; it certainly doesn't throw any errors playing with it in the JS Fiddle demo (attached), and I think clearly shows that selecting from the radio <input> elements is required.
It seems that with the download attribute present that the download is initiated before the execution of the function you had attached via the onclick in-line event-handler (which is obtrusive JavaScript, and is why I bound events in my demo entirely in JavaScript, though I did bind a lot of data to the elements in the HTML), in this attempted solution I remove that download attribute and only add it, via JavaScript, once one of the radios is selected.
It is not enough to have the getCv function return false. You need to write the return false into the onclick itself or have the result of the getCv function call be returned inline in the onclick itself:
<a href="#" id="cvLink" download onclick="return getCv();">
Also, the return value of the getCv function should depend on whether you want the link to be executed:
function getCv() {
if(document.getElementById('radio1').checked) {
document.getElementById('cvLink').href = "https://drive.google.com/uc?export=download&id=MZTFCWnRYbnlvclk";
return true;
}
else if(document.getElementById('radio2').checked) {
document.getElementById('cvLink').href = "https://drive.google.com/uc?export=download&id=uK6ct7MZ2N6Ni1qQUFyWXM";
return true;
}
else if(document.getElementById('radio3').checked) {
document.getElementById('cvLink').href = "https://drive.google.com/uc?export=download&id=0VDenJqUldud2M";
return true;
}
else
{
alert('Please Select Any Format To Download!!');
return false;
}
}
You should add an "return false;" statement to the end of the getCv function.
This will prevent the a from executing.

Updating JavaScript function for multiple individual elements

I wrote the following code for an example of standard checkboxes vs. ARIA checkboxes and included the CSS and JS in one file so it can be copied/pasted. I haven't written JS in a while and I got the function I want working by calling an element by its id. I have multiple elements and I'd like to update the function to work for each one. I know it's super easy but, as I said, I haven't written JS in some time. I have the following checkboxes written by including ARIA attributes to span elements.
<fieldset>
<legend id="check_title">ARIA Checkboxes</legend>
<p>Checkboxes using ARIA and JavaScript:</p>
<div role="application">
<div class="checkboxes" aria-labelledby="check_title">
<!-- The "aria-labelledby" attribute is required because label elements can only be applied to form elements. -->
<!-- We are using span elements instead of default HTML checkbox inputs so aria-labelledby is needed for association. -->
<span role="checkbox" tabindex="0" aria-checked="false" aria-labelledby="labelA" id="optionA" onclick="toggleState();" onkeyup="ARIA_Checkbox_Key(event);">
<img src="unchecked.png" alt="" role="presentation" id="imageA">
<label id="labelA">Option A</label>
</span>
<br />
<span role="checkbox" tabindex="0" aria-checked="false" aria-labelledby="labelB" id="optionB" onclick="toggleState();" onkeyup="ARIA_Checkbox_Key(event);">
<img src="unchecked.png" alt="" role="presentation" id="imageB">
<label id="labelB">Option B</label>
</span>
</div>
</div>
</fieldset>
Then I have the following JavaScript to toggle the aria-checked attribute and the image from unchecked to checked:
<script type="text/javascript">
// This function binds the event keycode 32 (space bar) to run the function toggleState
// This is needed since the default functionality of a check box is triggered with the space bar
function ARIA_Checkbox_Key(event) {
if(event.keyCode == 32) {
toggleState()
}
}
// This function gets the aria-checked attribute of an element. If it is false, it makes it true and vice versa.
function toggleState() {
var getvalue=document.getElementById("optionA").getAttribute("aria-checked");
if (getvalue=="false") {
document.getElementById("optionA").setAttribute("aria-checked", "true");
document.getElementById("imageA").setAttribute("src", "checked.png");
} else {
document.getElementById("optionA").setAttribute("aria-checked", "false");
document.getElementById("imageA").setAttribute("src", "unchecked.png");
}
}
</script>
Clicking the image or label for Option A or Option B will toggle the class and image for Option A. This code currently works but what I can't remember and for the life of me can't figure out what to google is how to update this to account for each individual checkbox. I believe I need to create an array then reference the right point in the array but I don't recall how to accomplish that.
You need to pass through the target to the functions:
onclick="toggleState(this);"
onkeyup="ARIA_Checkbox_Key(event);"
Then for the event, use the event target:
function ARIA_Checkbox_Key(event) {
if (event.keyCode == 32) {
toggleState(event.target);
}
}
And once the target element is passed through you can get the child using getElementsByTagName:
function toggleState(el) {
var img = el.getElementsByTagName('img')[0],
getvalue = el.getAttribute("aria-checked");
if (getvalue == "false") {
console.log('toggleState', true);
el.setAttribute("aria-checked", "true");
img.setAttribute("src", "checked.png");
} else {
console.log('toggleState', false);
el.setAttribute("aria-checked", "false");
img.setAttribute("src", "unchecked.png");
}
}

Categories