randy
randy

Reputation: 217

Show / Hide Elements within the same parent div

I'm having trouble getting a div ('.option-other') within a parent group ('.other-row') to show/hide when the corresponding option of the select element ('.select-toggle') is selected. Right now if "other" is selected from either question set 1 or 2 it will show both of the '.option-other' divs. I tried using .parent() and .closest() as described in this solution, but can't seem to figure out the proper way to utilize it for this use case.

$(".select-toggle").change(function() {
  var oth = false;
  $(".select-toggle option:selected").each(function() {
    if ($(this).val() == "other") oth = true;
  });
  if (oth) $('.option-other').show();
  else $('.option-other').hide();

  // tried this method as well but still doesnt work
  // if (oth) $(this).closest('.other-row').children('.option-other').show();
  // else $(this).closest('.other-row').children('.option-other').hide();
}).change();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Question set 1 -->
<div class="wrapper other-row">
  <div class="col">
    <div class="form-group">
      <label>What stuff do you eat?</label>
      <select class="select-toggle" multiple>
            <option>Pizza</option>
            <option>Cake</option>
            <option value="other">Other</option>
          </select>
    </div>
  </div>
  <div class="col">
    <div class="form-group option-other">
      <label>Other</label>
      <input type="text" placeholder="what other stuff do you like" />
    </div>
  </div>
</div>

<!-- Question set 2 -->
<div class="wrapper other-row">
  <div class="col">
    <div class="form-group">
      <label>What stuff do you drink?</label>
      <select class="select-toggle" multiple>
            <option>Water</option>
            <option>Soda</option>
            <option value="other">Other</option>
          </select>
    </div>
  </div>
  <div class="col">
    <div class="form-group option-other">
      <label>Other</label>
      <input type="text" placeholder="what other stuff do you like" />
    </div>
  </div>
</div>

Upvotes: 1

Views: 556

Answers (2)

AuxTaco
AuxTaco

Reputation: 5171

// you wrote:
// tried this method as well but still doesnt work
// if (oth) $(this).closest('.other-row').children('.option-other').show();
// else $(this).closest('.other-row').children('.option-other').hide();

You're close, but $.children only selects direct children of each .other-row. Since .option-other is inside .col inside .other-row, $.children can't see it. Use $.find instead.

// your original code:
var oth = false;
$(".select-toggle option:selected").each(function() {
  if ($(this).val() == "other") oth = true;
});

This sets one visibility value for the entire page: if at least one "other" option is selected, anywhere, show all the text inputs. The change event is fired for the <select> that actually changed, so focus your efforts there:

var oth = false;
$(this).children("option:selected").each(function() {
  if ($(this).val() == "other") oth = true;
});
if (oth) $(this).closest('.other-row').find('.option-other').show();
else $(this).closest('.other-row').find('.option-other').hide();

This works, but it could be cleaner. Showing or hiding an element based on a boolean is a common enough requirement that jQuery has a function for it: $.toggle. You can replace the if/else lines with

$(this).closest('.other-row').find('.option-other').toggle(oth);

Your $.each loop does one thing: set oth if there exists at least one selected <option> with a value of "other". You can get the same logic as a one-liner by using an attribute selector:

var oth = ($(this).find('option:checked[value="other"]').length !== 0);

(I changed :selected to :checked because you're already filtering on option elements, and :selected has a performance penalty.)

The final version:

$(".select-toggle").change(function() {
  var oth = ($(this).find('option:checked[value="other"]').length !== 0);
  $(this).closest('.other-row').find('.option-other').toggle(oth);
}).change();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Question set 1 -->
<div class="wrapper other-row">
  <div class="col">
    <div class="form-group">
      <label>What stuff do you eat?</label>
      <select class="select-toggle" multiple>
            <option>Pizza</option>
            <option>Cake</option>
            <option value="other">Other</option>
          </select>
    </div>
  </div>
  <div class="col">
    <div class="form-group option-other">
      <label>Other</label>
      <input type="text" placeholder="what other stuff do you like" />
    </div>
  </div>
</div>

<!-- Question set 2 -->
<div class="wrapper other-row">
  <div class="col">
    <div class="form-group">
      <label>What stuff do you drink?</label>
      <select class="select-toggle" multiple>
            <option>Water</option>
            <option>Soda</option>
            <option value="other">Other</option>
          </select>
    </div>
  </div>
  <div class="col">
    <div class="form-group option-other">
      <label>Other</label>
      <input type="text" placeholder="what other stuff do you like" />
    </div>
  </div>
</div>

Vanilla JS version:

document.querySelectorAll('.select-toggle').forEach(el => {
  el.addEventListener('change', evt => {
    const oth = evt.target.querySelector('option:checked[value="other"]');
    evt.target
      .closest('.other-row')
      .querySelector('.option-other')
      .style.display = (oth ? '' : 'none');
  });

  // trigger change event programmatically
  const event = document.createEvent('HTMLEvents');
  event.initEvent('change', true, false);
  el.dispatchEvent(event);
});

Upvotes: 1

JSONaLeo
JSONaLeo

Reputation: 416

Here is a solution that is a little clunky but I did it relatively quick. It's kind of a work around for having to know which of your two selectors with the same class had been selected.

Here is a working example using your code.

$(".select-toggle").change(function () {
  var oth = false;
  $(".select-toggle option:selected").each(function () {
    if ($(this).val() == "otherFood") {
      oth = true; 
      $('.option-other-food').show();
    } else {
      $('.option-other-food').hide();
    };
    if ($(this).val() == "otherDrink") {
      oth = true; 
      $('.option-other-drink').show();
    } else {
      $('.option-other-drink').hide();
    };
  });
}).change();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Question set 1 -->
<div class="wrapper other-row">
  <div class="col">
    <div class="form-group">
      <label>What stuff do you eat?</label>
      <select class="select-toggle" multiple>
        <option>Pizza</option>
        <option>Cake</option>
        <option value="otherFood">Other</option>
      </select>
    </div>
  </div>
  <div class="col">
    <div class="form-group option-other-food">
      <label>Other</label>
      <input type="text" placeholder="what other stuff do you like"/>
    </div>
  </div>
</div>

<!-- Question set 2 -->
<div class="wrapper other-row">
  <div class="col">
    <div class="form-group">
      <label>What stuff do you drink?</label>
      <select class="select-toggle" multiple>
        <option>Water</option>
        <option>Soda</option>
        <option value="otherDrink">Other</option>
      </select>
    </div>
  </div>
  <div class="col">
    <div class="form-group option-other-drink">
      <label>Other</label>
      <input type="text" placeholder="what other stuff do you like"/>
    </div>
  </div>
</div>

Cheers!

Upvotes: 0

Related Questions