Search code examples
jqueryparent-child

Different jQuery function based on parent class


I have a switch that changes parent class to a div, and based on that parent class, the links inside that parent do different things. I wrote it like it's CSS :D

// if the parent is .major, do this:
$(".major .menu a").click(function(e){
    $(".minor-result").removeClass("act");
    $(".major-result").addClass("act");
    e.preventDefault();
});
// if the parent is .minor, do this:
$(".minor .menu a").click(function(e){
    $(".major-result").removeClass("act");
    $(".minor-result").addClass("act");
    e.preventDefault();
});

Also, there will be seven different parent classes. It can't be a toggle and I really need those add/remove rules for child elements.

I understand that jQuery is binding that function to the existing parent-child combo and changing parent classes doesn't change the function.

Edit: One cleaver solution would be to put 7 unique links inside each menu li and those links would be display: block/none with CSS, based on parent class. If each link has only one function, there's no longer a problem. But maybe jQuery can simplify it by swapping 7 options.

// swap classes for #scale 
$(".make-minor a").click(function(e){
    $("#scale").removeClass("major");
    $("#scale").addClass("minor");
    e.preventDefault();
});
$(".make-major a").click(function(e){
    $("#scale").removeClass("minor");
    $("#scale").addClass("major");
    e.preventDefault();
});
// here is the part I struggle with:
// if the parent is .major, do this:
$(".major .menu a").click(function(e){
    $(".minor-result").removeClass("act");
    $(".major-result").addClass("act");
    e.preventDefault();
});
// if the parent is .minor, do this:
$(".minor .menu a").click(function(e){
    $(".major-result").removeClass("act");
    $(".minor-result").addClass("act");
    e.preventDefault();
});
.page-body {margin:20px auto;width:200px;}
a {text-decoration:none;padding:5px 10px;display:inline-block;}

.make-minor a {background:blue;color:#fff;}
.make-major a {background:red;color:#fff;}

.major .menu a {color:orange;}
.minor .menu a {color:teal;}

.act {display:block !important;}
.major-result, .minor-result {display:none;}

.major-result a {color:red;}
.minor-result a {color:blue;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div class="page-body">
  
<div class="make-major"><a href="">make it Major</a></div>
<div class="make-minor"><a href="">make it minor</a></div>

<div id="scale" class="major"><!-- can be .minor -->
  <ul id="wrap" class="menu">
    <li id="one"><a href="">I</a></li>
    <li id="two"><a href="">ii</a></li>
    <li id="three"><a href="">III</a></li>
  </ul>
</div>

<ul class="major-result act">
  <li><a href="">One</a></li>
  <li><a href="">Two</a></li>
  <li><a href="">Three</a></li>
</ul>
<ul class="minor-result">
  <li><a href="">one minor</a></li>
  <li><a href="">two minor</a></li>
  <li><a href="">three minor</a></li>
</ul>
  
</div>


Solution

  • The four click listeners can be replaced with two:

    1. Finds a target action name in the class list of a parent, then removes previous and adds the current action to #scale element classes.
    2. Removes an act class from result elements, builds the .ACTION_NAME-result selector with current #scale action name, finds an element using that selector, and finally adds an act class to it.

    General CSS classes make and result were added to simplify the script and styling.

    Five color actions have been added to demonstrate the seven different parent classes. All classes (including major, minor) are listed in actions variable at the beginning of a script.

    $(function() {
      // list of action names
      const actions = ["major", "minor", "green", "aqua", "gray", "fuchsia", "orange"];
    
      // swap classes for #scale 
      $(".make a").click(function(e) {
        const make = $(this).closest(".make");
        const makeActions = actions.filter(function(act) {
          return make.hasClass("make-" + act);
        });
        $("#scale").removeClass(actions);
        $("#scale").addClass(makeActions);
        e.preventDefault();
      });
    
      // find an action class and activate its result
      $("#scale .menu a").click(function(e) {
        const scale = $(this).closest("#scale");
        $(".result").removeClass("act");
        actions.forEach(function(act) {
          if (scale.hasClass(act)) {
            $("." + act + "-result").addClass("act");
          }
        });
        e.preventDefault();
      });
    });
    .page-body {
      margin: 20px auto;
      width: 200px;
    }
    
    a {
      text-decoration: none;
      padding: 5px 10px;
      display: inline-block;
    }
    
    
    /* Make links */
    
    .make a {
      color: #fff;
    }
    
    .make-minor a {
      background: blue;
    }
    
    .make-major a {
      background: red;
    }
    
    .make-green a {
      background: green;
    }
    
    .make-aqua a {
      background: aqua;
    }
    
    .make-gray a {
      background: gray;
    }
    
    .make-fuchsia a {
      background: fuchsia;
    }
    
    .make-orange a {
      background: orange;
    }
    
    
    /* Results */
    
    .result {
      display: none;
    }
    
    .result.act {
      display: block;
    }
    
    
    /* Menu and result colors */
    
    .major .menu a,
    .major-result a {
      color: red;
    }
    
    .minor .menu a,
    .minor-result a {
      color: blue;
    }
    
    .green .menu a,
    .green-result a {
      color: green;
    }
    
    .aqua .menu a,
    .aqua-result a {
      color: aqua;
    }
    
    .gray .menu a,
    .gray-result a {
      color: gray;
    }
    
    .fuchsia .menu a,
    .fuchsia-result a {
      color: fuchsia;
    }
    
    .orange .menu a,
    .orange-result a {
      color: orange;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    
    
    <div class="page-body">
    
      <div class="make-major make"><a href="">make it Major</a></div>
      <div class="make-minor make"><a href="">make it minor</a></div>
      <div class="make-green make"><a href="">make it green</a></div>
      <div class="make-aqua make"><a href="">make it aqua</a></div>
      <div class="make-gray make"><a href="">make it gray</a></div>
      <div class="make-fuchsia make"><a href="">make it fuchsia</a></div>
      <div class="make-orange make"><a href="">make it orange</a></div>
    
      <div id="scale" class="major">
        <!-- can be .minor, .green, .aqua, ... -->
        <ul id="wrap" class="menu">
          <li id="one"><a href="">I</a></li>
          <li id="two"><a href="">ii</a></li>
          <li id="three"><a href="">III</a></li>
        </ul>
      </div>
    
      <ul class="major-result result act">
        <li><a href="#">One</a></li>
        <li><a href="#">Two</a></li>
        <li><a href="#">Three</a></li>
      </ul>
      <ul class="minor-result result">
        <li><a href="#">one minor</a></li>
        <li><a href="#">two minor</a></li>
        <li><a href="#">three minor</a></li>
      </ul>
      <ul class="green-result result">
        <li><a href="#">one green</a></li>
        <li><a href="#">two green</a></li>
        <li><a href="#">three green</a></li>
      </ul>
      <ul class="aqua-result result">
        <li><a href="#">one aqua</a></li>
        <li><a href="#">two aqua</a></li>
        <li><a href="#">three aqua</a></li>
      </ul>
      <ul class="gray-result result">
        <li><a href="#">one gray</a></li>
        <li><a href="#">two gray</a></li>
        <li><a href="#">three gray</a></li>
      </ul>
      <ul class="fuchsia-result result">
        <li><a href="#">one fuchsia</a></li>
        <li><a href="#">two fuchsia</a></li>
        <li><a href="#">three fuchsia</a></li>
      </ul>
      <ul class="orange-result result">
        <li><a href="#">one orange</a></li>
        <li><a href="#">two orange</a></li>
        <li><a href="#">three orange</a></li>
      </ul>
    
    </div>