Array item is undefined

I want to show/hide form inputs if particular radio buttons are selected.

I moved the hide functionality into a function to reduce repetition of code, but each time a radio button is checked I get the error: elems[i] is undefined

Can someone advise why this is occuring?

<form>
          <fieldset id="contact-methods">
            <legend>Preferred contact method</legend>
            <div>
              <input type="radio" id="phoneyes" name="preferred-method">
              <label for="phoneyes" class="radio-label">Phone</label>
              <input id="yourphone" name="Yourphone" value="enter phone number" class="hint dependant">
            </div>
            <div>
              <input type="radio" id="emailyes" name="preferred-method">
              <label for="emailyes" class="radio-label">Email</label>
              <input id="youremail" name="Email" value="enter email address" class="hint dependant">
            </div>
            <div>
              <input type="radio" id="postyes" name="preferred-method" class="textarea-label">
              <label for="postyes" class="textarea-label radio-label">Post</label>
              <textarea id="youraddress" rows="2" cols="40" name="Address" class="hint dependant">enter postal address</textarea>
            </div>
          </fieldset>
</form>
	// Initially disable and hide depandant inputs.
  $('.dependant').each(function(){
	$(this).attr('disabled', true).hide();
  });
  function disableElem(elems){
	  var i = 0;
	  for ( i=0; i <= elems.length; i++){
		  elems[i].attr('disabled', true).hide();
	  }
  }
  // Show/hide contact methods when checked
  $('#contact-methods').click(function(e){
	 var method = $(e.target).attr('id');
	 if(method === 'phoneyes'){
		 $('#yourphone').removeAttr('disabled').show();
		 hideOptions = [$('#youremail'), $('#youraddress')];
		 disableElem(hideOptions)
	 }
	 if(method === 'emailyes'){
		 $('#youremail').removeAttr('disabled').show();
		 hideOptions = [$('#yourphone'), $('#youraddress')];
		 disableElem(hideOptions)
	 }
	 if(method === 'postyes'){
		 $('#youraddress').removeAttr('disabled').show();
		 hideOptions = [$('#youremail'), $('#yourphone')];
		 disableElem(hideOptions)
	 }
  });// closing show/hide contact methods

I wouldn’t create a function for this, but just do


$('#youremail,#youraddress').attr('disabled', true).hide();

All of that code could be entirely replaced with this:


$(function () {
    // Show/hide contact methods when checked
    $('#contact-methods').click(function (e) {
        $('.dependant').hide();
        $('.dependant', $(e.target).parent('div')).show();
    });

    // perform click function to initially hide dependant fields
    $('#contact-methods').click();
});

Thanks Paul!

I knew this should be achievable with less code than I had. Would you mind explaining line 5. I’m not entirly sure what’s going on there.

$('.dependant', $(e.target).parent('div')).show();

To break it up:

$(e.target)

e.target is the target of the event - i.e. the input field that was clicked. So, $(e.target) is a jQuery object for that target.

$(e.target).parent('div')

Gets the closest ancestor for $(e.target) that is a ‘div’

So for example when I click phone, $(e.target).parent(‘div’) will point to this div:


<div> <!-- <~~ That is $(e.target).parent('div') if I select "phone" -->
  <input type="radio" id="phoneyes" name="preferred-method">
  <label for="phoneyes" class="radio-label">Phone</label>
  <input id="yourphone" name="Yourphone" value="enter phone number" class="hint dependant">
</div> 

$('.dependant', $(e.target).parent('div'))

Selects an element with class “dependent” that is a child (or grand child, or grand grand child, or …) of the div that is selected by $(e.target).parent(‘div’)

I assume I don’t have to explain .show() :slight_smile:

Thanks ScallioXTX, very helpful!

I’ve got my head around .show() already :slight_smile:

My apologies for not replying before, but I’m currently somewhat distracted by an earthquake disaster that has befallen my city.

It’s good to know that you’re on track though, and I should be able to arrange a more permanent on-going presence here in a few days to come.