Search code examples
javascriptjqueryhtmltoggleparent

Toggle Class Only in One Parent


I have the code below that changes the class of a selection so that the user can only select one out of all the options. When there's one set of products per page, it's easily done but when I introduce two sets or more, the users can only select one between multiple groups.

I need a way to ensure that the toggling of the class only applies within the parent div of each button.

I.e. a user can select button 1 and button 3 but not button 1 and 2 or button 3 and 4

Updated

Only the product sets can have IDs

Products themselves as well as buttons can't have individual IDs

var box = $(".Button");
box.click(function() {
  $(this).toggleClass("Green");
  box.not(this).removeClass("Green");
});
.Label {
  font-weight: 600;
  padding: 5%;
  font-size: 16px;
  float: center;
  position: relative;
}

.Button {
  font-weight: bold;
  font-size: 13px;
  background: #0096db;
  text-align: center;
  border-bottom-left-radius: 5px;
  border-bottom-right-radius: 5px;
  border-top-left-radius: 5px;
  border-top-right-radius: 5px;
  padding: 15px;
  color: #fff;
  position: static;
  float: left;
  min-width: 25%;
  max-width: 40%;
}

.Button.Green {
  background: #64B448;
  font-weight: bold;
  font-size: 13px;
  text-align: center;
  border-bottom-left-radius: 5px;
  border-bottom-right-radius: 5px;
  border-top-left-radius: 5px;
  border-top-right-radius: 5px;
  padding: 15px;
  color: #fff;
  position: static;
  float: left;
  min-width: 25%;
  max-width: 40%;
}

.productset1 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 2fr));
  grid-template-rows: repeat(auto-fit, minmax(10px, 1fr));
  grid-gap: 5px;
}
.productset2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 2fr));
  grid-template-rows: repeat(auto-fit, minmax(10px, 1fr));
  grid-gap: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>
  <span>Product Set 1</span>
</h1>

<div class="productset1">
  <div class="product">
  <span class="Button">
  <span class="Label">Button 1</span>
  </span>
  </div>
    <div class="product">
  <span class="Button">
  <span class="Label">Button 2</span>
  </span>
  </div>
    <div class="product">
  <span class="Button">
  <span class="Label">Button 3</span>
  </span>
  </div>
    <div class="product">
  <span class="Button">
  <span class="Label">Button 4</span>
  </span>
  </div>
</div>


<h1>
  <span>Product Set 2</span>
</h1>

<div class="productset2">
  <div class="product">
  <span class="Button">
  <span class="Label">Button 5</span>
  </span>
  </div>
    <div class="product">
  <span class="Button">
  <span class="Label">Button 6</span>
  </span>
  </div>
    <div class="product">
  <span class="Button">
  <span class="Label">Button 7</span>
  </span>
  </div>
      <div class="product">
  <span class="Button">
  <span class="Label">Button 8</span>
  </span>
  </div>

</div>


Solution

  • Only look for other buttons within the parent:

    var box = $(".Button");
    box.click(function() {
      var $this = $(this);
      $this.toggleClass("Green");
      $this.parent().find(".Button").not(this).removeClass("Green");
    });
    

    Example:

    var box = $(".Button");
    box.click(function() {
      var $this = $(this);
      $this.toggleClass("Green");
      $this.parent().find(".Button").not(this).removeClass("Green");
    });
    .Button {
      font-weight: bold;
      font-size: 13px;
      background: #0096db;
      text-align: center;
      border-bottom-left-radius: 5px;
      border-bottom-right-radius: 5px;
      border-top-left-radius: 5px;
      border-top-right-radius: 5px;
      padding: 15px;
      color: #fff;
      position: static;
      float: right;
      min-width: 25%;
      max-width: 40%;
    }
    
    .Button.Green {
      background: #64B448;
      font-weight: bold;
      font-size: 13px;
      text-align: center;
      border-bottom-left-radius: 5px;
      border-bottom-right-radius: 5px;
      border-top-left-radius: 5px;
      border-top-right-radius: 5px;
      padding: 15px;
      color: #fff;
      position: static;
      float: right;
      min-width: 25%;
      max-width: 40%;
    }
    
    .productset1 {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 2fr));
      grid-template-rows: repeat(auto-fit, minmax(10px, 1fr));
      grid-gap: 5px;
    }
    .productset2 {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 2fr));
      grid-template-rows: repeat(auto-fit, minmax(10px, 1fr));
      grid-gap: 5px;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <h1>Product Set 1</h1>
    
    <div class="productset1">
    <span class="Button">Button 1</span>
    <span class="Button">Button 2</span>
    </div>
    
    <h1>Product Set 2</h1>
    
    <div class="productset2">
    <span class="Button">Button 3</span>
    <span class="Button">Button 4</span>
    </div>


    Or, as David Thomas pointed out, get it without script with radio inputs:

    Example:

    .Button {
      font-weight: bold;
      font-size: 13px;
      background: #0096db;
      text-align: center;
      border-bottom-left-radius: 5px;
      border-bottom-right-radius: 5px;
      border-top-left-radius: 5px;
      border-top-right-radius: 5px;
      padding: 15px;
      color: #fff;
      position: static;
      float: right;
      min-width: 25%;
      max-width: 40%;
    }
    
    input[type=radio] {
      display: none;
    }
    
    input[type=radio]:checked + .Button {
      background: #64B448;
      font-weight: bold;
      font-size: 13px;
      text-align: center;
      border-bottom-left-radius: 5px;
      border-bottom-right-radius: 5px;
      border-top-left-radius: 5px;
      border-top-right-radius: 5px;
      padding: 15px;
      color: #fff;
      position: static;
      float: right;
      min-width: 25%;
      max-width: 40%;
    }
    
    .productset1 {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 2fr));
      grid-template-rows: repeat(auto-fit, minmax(10px, 1fr));
      grid-gap: 5px;
    }
    .productset2 {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 2fr));
      grid-template-rows: repeat(auto-fit, minmax(10px, 1fr));
      grid-gap: 5px;
    }
    <h1>Product Set 1</h1>
    
    <div class="productset1">
    <input id="btn1" type="radio" name="set1">
    <label for="btn1" class="Button">Button 1</label>
    <input id="btn2" type="radio" name="set1">
    <label for="btn2" class="Button">Button 2</label>
    </div>
    
    <h1>Product Set 2</h1>
    
    <div class="productset2">
    <input id="btn3" type="radio" name="set2">
    <label for="btn3" class="Button">Button 3</label>
    <input id="btn4" type="radio" name="set2">
    <label for="btn4" class="Button">Button 4</label>
    </div>

    ...but it does increase the complexity of the markup. :-)