ron_g
ron_g

Reputation: 1663

set javascript variable using html attribute

I am trying to re-create the functionality of https://chriscoyier.net/ where you have a form with radio buttons, and as you click a radio button, the text changes.

What I started with was:

window.onload=function() {

  document.getElementById("hidden_elements").style.display="none";

  //  attach the click event handler to the radio buttons
  var radios = document.forms[0].elements["group1"];
  for (var i = [0]; i < radios.length; i++)
    radios[i].onclick=radioClicked;
}

function radioClicked() {
   if (this.value == "two") {
    document.getElementById("hidden_elements").style.display="block";
   } else {
    document.getElementById("hidden_elements").style.display="none";
   }
}
<form id="picker" method="post" action="">
Item 1: <input type="radio" name="group1" value="one" />
Item 2: <input type="radio" name="group1" value="two" />
Item 3: <input type="radio" name="group1" value="three" /><br />
<br />
<div id="hidden_elements">
Input 1: <input type="text" id="intext" />
Input 2: <input type="text" id="intext2"  />
Input 3: <input type="text" id="intext3"  /><br /><br />
</div>
<input type="submit" id="submitbutton" value="Send form" />
</form>

This allows me hide or display the div with id="hidden_elements" if input number 2 is selected.

What I want to do is hide or display the individual elements of "hidden_elements" based on the input 1, 2 or 3.

I tried changing the "hidden_elements" attributes to:

<div id="hidden_elements">
Input 1: <input type="text" name="one" />
Input 2: <input type="text" name="two"  />
Input 3: <input type="text" name="three"  /><br /><br />
</div>

and JS to:

var hide = document.getElementById("hidden_elements");
        for (var i = [0]; i < hide.length; i++)
            hide[i].style.display = "none";

function radioClicked() {
        document.getElementsByName(this.value).style.display = "block"
    }

But that doesn't work either.

I've tried a less appealing approach using if/else statements, but that too doesn't work.

<div id="paragraphs">
    <div id="hidden_element" name="one">Paragraph 1 </div>
    <div id="hidden_element" name="two">Paragraph 2 </div>
    <div id="hidden_element" name="three">Paragraph 3 </div>
</div>

function radioClicked() {
        if (this.value == "one") {
            document.getElementById("hidden_element_one").style.display="block";
        } else if (this.value == "two") {
            document.getElementById("hidden_element_two").style.display="block";
        } else if (this.value == "three") {
            document.getElementById("hidden_element_three").style.display="block";
        }
    }

I've tried a few more approaches but the behaviour isn't what I want. Any idea how I can change the display from "none" to "block" based on the selected radio-button? (I know you can do it with JQuery but I'm trying to learn Javascript)

Upvotes: 1

Views: 1350

Answers (4)

T.J. Crowder
T.J. Crowder

Reputation: 1074355

A few notes:

  1. getElementsByName returns a list of elements. That list doesn't have a style property (the entries on the list do).

  2. ids must be unique, you can't put the same ID on multiple elements. Use a class to group elements together.

  3. data-* attributes would probably be a better choice than name, since you can use them on any element type.

  4. If you want to show/hide elements based on the radio button value, you'll need to select all of the elements you show/hide, not just the one matching the radio button's value. Then loop through that list, showing/hiding depending on whether they match the selected value.

  5. The load event happens very late in the page load cycle (e.g., right at the end). Instead of using load, put your script tags at the very end of your document, just before the closing </body> tag, and do your event hook-up immediately.

  6. I'd probably use a class to toggle visibility rather than style.display.

  7. You can get the attribute from an element via getAttribute.

  8. You can use querySelectorAll to get a list of elements matching any CSS selector. Use it on document to look globally, or on a specific element to only look within that element. For instance, to get a list of elements in the document with an attribute called data-val, you'd use the CSS selector [data-val], e.g. `document.querySelectorAll("[data-val]").

Here's a version of your snippet with some minimal updates; see comments:

// I'd use querySelectorAll rather than the old-style
// forms and elements collections (but those work too)
var radios = document.querySelectorAll("#picker input[type=radio]");
// Initial value is 0, not [0]
for (var i = 0; i < radios.length; i++) { // You were missing { on this line
    // Recommend modern event handling, not onclick
    radios[i].addEventListener("click", radioClicked);
}

function radioClicked() {
    var hidden = document.getElementById("hidden_elements");
    hidden.classList.remove("hidden");
    // Get all elements within it that have a data-val attribute
    var list = hidden.querySelectorAll("[data-val]");
    for (var i = 0; i < list.length; ++i) {
        var el = list[i];
        // Add/remove the hidden class depending on whether it matches
        el.classList.toggle("hidden", el.getAttribute("data-val") != this.value);
    }
}
.hidden {
  display: none;
}
<form id="picker" method="post" action="">
Item 1: <input type="radio" name="group1" value="one" />
Item 2: <input type="radio" name="group1" value="two" />
Item 3: <input type="radio" name="group1" value="three" /><br />
<br />
<!-- Hide this initially with markup rather than code -->
<div id="hidden_elements" class="hidden">
<!-- Use data-val to identify them -->
Input 1: <input type="text" data-val="one" />
Input 2: <input type="text" data-val="two"  />
Input 3: <input type="text" data-val="three"  /><br /><br />
</div>
<input type="submit" id="submitbutton" value="Send form" />
</form>

Some further changes you might make:

  • Wrap all the code in an IIFE so nothing is global.
  • Wrap the inputs and their labels in label elements, and toggle the visibility of them rather than the inputs directly.
  • Wrap things in containers for line breaks rather than using br.

Upvotes: 2

user6083685
user6083685

Reputation:

My solution add extra div for all inputs and id for this div

window.onload = function() {

    var hide = document.getElementsByClassName("hidden");
    for (var i = [0]; i < hide.length; i++)
        hide[i].style.display = "none";


    //  attach the click event handler to the radio buttons
    var radios = document.forms[0].elements["group1"];
    for (var i = [0]; i < radios.length; i++)
        radios[i].onclick = radioClicked;
}


function radioClicked() {
    var hide = document.getElementsByClassName("hidden");
    for (var i = [0]; i < hide.length; i++)
        hide[i].style.display = "none";
    document.getElementById("hidden_" + this.value).style.display = "block"
}
<form id="picker" method="post" action="">
Item 1: <input type="radio" name="group1" value="one" />
Item 2: <input type="radio" name="group1" value="two" />
Item 3: <input type="radio" name="group1" value="three" /><br />
<br />
<div id="hidden_elements">
  <div class="hidden" id="hidden_one">Input 1: <input type="text"  /></div>
  <div class="hidden" id="hidden_two">Input 2: <input type="text" /></div>
  <div class="hidden" id="hidden_three">Input 3: <input type="text"  /><br /><br /></div>
</div>
<input type="submit" id="submitbutton" value="Send form" />

Upvotes: 1

user9019817
user9019817

Reputation:

My solution changes the values of the radio buttons to the numeric value rather than the the text value. This enabled it to be used to select the input element by id and appending the number.

Each time radioClicked() is run it hides all the inputs and only shows the selected one. To do this I've wrapped all the inputs and their labels in span elements.

window.onload=function() {
  
  //  attach the click event handler to the radio buttons
  var radios = document.forms[0].elements["group1"];
  for (var i = [0]; i < radios.length; i++)
    radios[i].onclick=radioClicked;
    
}

function radioClicked() {

   var allRadio = document.querySelectorAll('#hidden_elements span');
      
   Array.prototype.forEach.call(allRadio, function(el, i){
      el.style.display="none";
   });
   
   var selectedRadio = this.value;
   document.getElementById("intext" + selectedRadio).parentNode.style.display="block";
   
}
#hidden_elements span {
display: none;
}
<form id="picker" method="post" action="">
Item 1: <input type="radio" name="group1" value="1" />
Item 2: <input type="radio" name="group1" value="2" />
Item 3: <input type="radio" name="group1" value="3" /><br />
<br />
<div id="hidden_elements">
<span>Input 1: <input type="text" id="intext1" /></span>
<span>Input 2: <input type="text" id="intext2"  /></span>
<span>Input 3: <input type="text" id="intext3"  /></span><br /><br />
</div>
<input type="submit" id="submitbutton" value="Send form" />
</form>

Upvotes: 1

hityagi
hityagi

Reputation: 5256

You could do something like this :

  1. Add a common class on the elements you want to toggle (can wrap label and field in span)

  2. Toggle their display, can use a css class for hiding and a class same as the value of the checkbox

function radioClicked(e) {
  //hide previously shown 
  var elem = document.getElementById("hidden_elements").getElementsByClassName("shown")[0];
  if (elem) {
    elem.classList.remove("shown");
    elem.classList.add("hide");
  }

  //show currently selected
  elem = document.getElementById("hidden_elements").getElementsByClassName(e.value)[0];
  elem.classList.remove("hide");
  elem.classList.add("shown");
}
.hide {
  display: none;
}
<form id="picker" method="post" action="">
  Item 1: <input type="radio" name="group1" value="one" onclick="radioClicked(this)" /> 
  Item 2: <input type="radio" name="group1" value="two" onclick="radioClicked(this)" /> 
  Item 3: <input type="radio" name="group1" value="three" onclick="radioClicked(this)" /><br />
  <br />
  <div id="hidden_elements">
    <span class="hide one elem">Input 1: <input type="text" id="intext" /></span>
    <span class="hide two elem">Input 2: <input type="text" id="intext2"  /></span>
    <span class="hide three elem">Input 3: <input type="text" id="intext3"  /></span>
  </div>
  <input type="submit" id="submitbutton" value="Send form" />
</form>

Upvotes: 1

Related Questions