5

Most of the similar questions that arose as I wrote this one were like this (where the user wishes to toggle an element's class using pure JS) or this (where the user wishes wishes to toggle other attributes using jQuery)

My question is a mixture of the two. I am aware that the el.classList.toggle() method exists for toggling an element's class using pure JS, but I wish to toggle different attributes using pure JS, specifically the checked attribute of some radio buttons, since this (annoyingly) does not change when different options are selected.

Is it possible to toggle the checked attribute on my two radio buttons with pure JS (by toggling I mean remove the attribute from the element altogether if it is present, and add it if it is not)?

radios = document.getElementsByName("Floor");
for (i = 0; i < radios.length; i++) {
    radios[i].addEventListener('change', function () {
        this.(/*checked attribute*/).toggle()
    }, false);
}
<input checked id="Floor" name="Floor" type="radio" value="0">Ground Floor
<input id="Floor" name="Floor" type="radio" value="1">First Floor

Edit: The possible duplicate question mentioned in the comments does not quite solve my problem. I don't need to change which radio button appears checked, I just want to toggle the checked attribute, to make it easier for me to reference the button that is checked later on in the code. Of course, if there is another, easier way of doing this, I'm all ears.

murchu27
  • 527
  • 2
  • 6
  • 20
  • [W3Schools `Element.setAttribute()`](https://www.w3schools.com/jsref/met_element_setattribute.asp) [MDN `Element.setAttribute()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute) – Patrick Barr Jul 26 '17 at 14:53
  • Also see - [DOM `.removeAttribute()`](https://developer.mozilla.org/docs/Web/API/Element/removeAttribute). As the "toggle" doesn't exist, you can easily create a function to do that. – evolutionxbox Jul 26 '17 at 14:54
  • 2
    You're giving two elements the same ID. That's not valid. They can have the same name, but IDs are unique. –  Jul 26 '17 at 14:54
  • 2
    Possible duplicate of [Javascript toggle checkbox](https://stackoverflow.com/questions/19155423/javascript-toggle-checkbox) – fredtantini Jul 26 '17 at 14:55
  • @Amy I actually just copied those lines from ChromeDev tools. In reality I am using MVC, and those elements are generated by Html.RadioButton, which seems to automatically assign the same id to both. In any case, I don't think it has anything to do with my problem – murchu27 Jul 26 '17 at 14:59
  • No, it doesn't, I was just letting you know your HTML isn't valid. –  Jul 26 '17 at 15:01
  • @Amy Again, it isn't HTML that I actually wrote, but thank you anyway – murchu27 Jul 26 '17 at 15:07
  • @evolutionxbox I'm pretty sure you're answering my question: you're saying there's no built in function in js similar to `el.classList.toggle()` to do what I'm looking for? And that I will have to write another function instead? – murchu27 Jul 26 '17 at 15:08
  • That's right, your MVC code renders into invalid HTML. –  Jul 26 '17 at 15:13
  • @Amy If you really want to know what my MVC code is: `@Html.RadioButton("Floor", 0, true) Ground Floor&nbsp
    ` `@Html.RadioButton("Floor", 1, true) First Floor&nbsp` Which in Chrome's element inspector results in: `` `Ground Floor ` `` `First Floor `
    – murchu27 Jul 26 '17 at 15:17
  • I didn't want to know that. https://stackoverflow.com/questions/2801401/radio-button-generates-duplicate-html-id-s –  Jul 26 '17 at 15:19
  • It seems I am... `el.attributes.toggle()` doesn't exist, but you could create it. – evolutionxbox Jul 26 '17 at 16:05

7 Answers7

7

There actually is an Element.toggleAttribute method for boolean attributes. MDN Docs.

However, since it is not supported in IE, you might want to add the MDN Polyfill

Mendy
  • 7,612
  • 5
  • 28
  • 42
4

there is no toggle method for attribute.

You can use:

elm[elm.hasAttribute('hidden')?'removeAttribute':'setAttribute']('hidden', '')

or

elm.hasAttribute('hidden') ? removeAttribute('hidden') : setAttribute('hidden')

EDIT: there is now toggle method for attribute.

elm.toggleAttribute('hidden')

https://developer.mozilla.org/docs/Web/API/Element/hasAttribute

Yukulélé
  • 15,644
  • 10
  • 70
  • 94
  • 2
    Use " [hasAttribute](https://developer.mozilla.org/es/docs/Web/API/Element/hasAttribute) " to check if attribute is defined – Jimmy Collazos Jul 02 '18 at 12:47
4

This will work definitely well

const attrToggle = (el, attr) => el.getAttribute(attr) == 'false' ? el.setAttribute(attr, "true") : el.setAttribute(
      attr, "false")

It's similar to native toggleAttribute.

Richard-Degenne
  • 2,892
  • 2
  • 26
  • 43
M. Inam
  • 301
  • 3
  • 7
1

I didn't test this, but this should do the trick.

radios = document.getElementsByName("Floor");
  for (i = 0; i < radios.length; i++) {
    radios[i].addEventListener('change', function () {
       if ( this.checked ) {
          this.setAttribute("checked", "false");
       } else {
          this.setAttribute("checked", "true");
       }
  }, false);
}
Nicolay Hekkens
  • 530
  • 5
  • 18
1

Element.toggleAttribute(name) used to toggle boolean attribute https://developer.mozilla.org/en-US/docs/Web/API/Element/toggleAttribute

this.toggleAttribute("checked");
karel
  • 5,489
  • 46
  • 45
  • 50
0

To anyone stumbling on this question, no one in comments or answers since 2017 seems to have pick up on the OP's incorrect assumptions on the true nature of the checked element attribute they are trying to 'toggle'. As this post has so far been viewed 19k times, here is the information you might actually be looking for:

<input type="radio" checked>

In this context the element's checked attribute is a flag developers can use to tell the browser to render a "checked" state on a radio or checkbox input on page load. After page load, the browser does not update or toggle this attribute when a user later selects or un-selects the input.

From MDN:

Checked: A Boolean attribute which, if present, indicates that this radio button is the default selected one in the group.

Therefore the approach of using Element.toggleAttribute('checked') suggested by some here, won't work as expected as the .toggleAttribute() method adds or removes the pre-render flag from the input, but doesn't update the element's 'checked' state as the OP is trying to do. Applying a boolean value to the attribute also has no effect on the state of the element: (this wont work) checked="false"

In JavaScript you can access the current state of an input through HTMLInputElement's IDL boolean property .checked, not to be confused with the Element attribute by the same name referenced by the OP. Here HTMLInputElement.checked is both a getter and setter, meaning you can access (and toggle the value of) .checked as follows:

<input type="radio" id="spam-machine" class="blackhat" name="spam-me" value="sure!">

<script>
    const spamMe = document.querySelector('#spam-machine');
    spamMe.checked = !spamMe.checked;
</script>

You can additionally selectively style checked inputs using the :checked CSS pseudo class:

input[type="radio"].blackhat:checked { visibility: hidden; }

Now go forth into the world .... rendering to no one evil for evil.

orionrush
  • 566
  • 6
  • 30
0

you can use the next function to toggle attributes by their value

// password hidden and visibility 
function toggle(id){
let element = document.getElementById(id);
element.getAttribute("type")==="password" ? element.setAttribute("type","text"):element.setAttribute("type","password");
}```