skip to Main Content

What is an effective way to write a JavaScript if-statement that transfers a data-active attribute from one div to another when a radio is checked?

If this has already been solved somewhere then please share a link. I can’t find one that does.

The goal is to navigate to the corresponding image when a radio is checked, and check the radio when the corresponding image is [data-active].

radio1.addEventListener('click', function(e){

        let radio1 = document.querySelector("#radio1");
        let radio2 = document.querySelector("#radio2");
        let radio3 = document.querySelector("#radio3");
    
        let first = document.getElementsByClassName("first");
        let second = document.getElementsByClassName("second");
        let third = document.getElementsByClassName("third");


        if(first = ["data-active"], "true"){
            radio1.classList.add("activeRad");
            radio1.classList.remove("inactiveRad");

        }
    });
<!-- Radio buttons -->
<div class="radio-inputs">
  <input class="radio-button" type="radio" name="radio-btn" id="radio1">
  <input class="radio-button" type="radio" name="radio-btn" id="radio2">
  <input class="radio-button" type="radio" name="radio-btn" id="radio3">
</div>

<!-- Carousel -->
<div class="list" data-slides>
  <div class="listItem first" data-active>
    <img src="https://placehold.co/100x100/000000/FFFFFF/png" alt="">
  </div>
  <div class="listItem second">
    <img src="https://placehold.co/100x100/000000/FFFFFF/png" alt="">
  </div>
  <div class="listItem third">
    <img src="https://placehold.co/100x100/000000/FFFFFF/png" alt="">
  </div>
</div>

3

Answers


  1. Instead of having multiple change events, I’m using a forEach loop on querySelectorAll looking for all radio-buttons.

    On each radio button I have a data-target attribute that corresponds to a matching data-id attribute on a div holding an image. I prefer this over IDs as IDs can get messy.

    In my event handler, I look for the radio button that was changed (via ev.target).

    I also look for anything that already has activeRad. If that exists, I remove that class so we don’t have duplicates.

    Then I simply use the target from the data-target to find the div to add the activeRad class to.

    Then at the very end I check to see if any divs already have the activeRad class. if so, take that div’s id and check the radio that has the matching data-target.

    I chose to use a single class instead of inactive and active as inactive can be achieved by targeting the .listItem in CSS.

    const radios = document.querySelectorAll(".radio-button");
    
    const handleRadio = (ev) => {
      const radio = ev.target;
      const hasActive = document.querySelector(".activeRad");
      if(hasActive)hasActive.classList.remove("activeRad");
      
      const target = document.querySelector("[data-id='" + radio.dataset.target + "']");
      target.classList.add("activeRad");
    }
    
    radios.forEach((r) => r.addEventListener("change",handleRadio))
    
    const hasActive = document.querySelector(".activeRad");
    
    if(hasActive){
      const target = document.querySelector("[data-target='" + hasActive.dataset.id + "']");
      target.checked = true;
    }
    .listItem{
      border:4px solid transparent;
      display:inline-block;
    }
    
    .listItem.activeRad{
      border-color:#ff0000;
    }
    <!-- Radio buttons -->
    <div class="radio-inputs">
      <input class="radio-button" data-target="1" type="radio" name="radio-btn" id="radio1">
      <input class="radio-button" data-target="2" type="radio" name="radio-btn" id="radio2">
      <input class="radio-button" data-target="3" type="radio" name="radio-btn" id="radio3">
    </div>
    
    <!-- Carousel -->
    <div class="list" data-slides>
      <div data-id="1" class="listItem first ">
        <img src="https://placehold.co/100x100/000000/ffffff" alt="">
      </div>
      <div data-id="2" class="listItem second activeRad">
        <img src="https://placehold.co/100x100/000000/ffffff" alt="">
      </div>
      <div data-id="3" class="listItem third">
        <img src="https://placehold.co/100x100/000000/ffffff" alt="">
      </div>
    </div>
    Login or Signup to reply.
  2. You shouldn’t be using data- attributes here (and you are not using them correctly). Instead, CSS classes are the way to go.

    Also, the use of id attributes, while simple enough, leads to brittle code that doesn’t scale easily. In most cases, you don’t need them though because there are several other ways to get element references (as you can see below).

    By avoiding the use of id and by setting up just one event handler that can handle click events from any element within it, the code below is very scalable. If you need to add more radio buttons and images, just update the HTML accordingly and you won’t need to touch the JS at all. 🙂

    There’s no need for an inactive class as an element becomes inactive as soon as the active class is removed from it.

    See comments inline below for details:

    // If you do need element references, get them just once (outside of the function)
    // rather than every time the function is called.
    // .getElementsByClassName() returns a live node-list of all
    // matching elements. It's an old API that is resource intensive
    // and should be avoided.
    
    // This will be used for indexing purposes
    const allRads = document.querySelectorAll(".radios > input[type='radio']");
    
    // This will be used to loop over all the div elements
    const allDivs = document.querySelectorAll(".listItem");
    
    // Set up just one event handler on the parent of the items
    // that could trigger the event
    document.querySelector(".radios").addEventListener("click", function(event){
      // First, check to see if the event was triggered by an element
      // we care to respond to:
      if(event.target.classList.contains("radTrigger")){
    
        // Loop over all the elements and remove the active class
        allDivs.forEach(function(item){
          item.classList.remove("active");
        });
      
        // Add the active class to the <div> who's index corresponds to the clicked
        // radio buttton's index.
        allDivs[Array.from(allRads).indexOf(event.target)].classList.add("active");
      }
    });
    /* Style this however you want, but classes are the way
       to go here, not data- attributes. */
    .active { border:2px solid red; }
    
    /* This is just for better visualization here at SO */
    .list > .listItem { display:inline-block; }
    <!-- Since the JS doesn't rely on data- attributes or id's
         you can see that it is much cleaner and doesn't require them. -->
    
    <!-- Radio buttons -->
    <div class="radios">
      <input class="radTrigger" type="radio" name="radio-btn">
      <input class="radTrigger" type="radio" name="radio-btn">
      <input class="radTrigger" type="radio" name="radio-btn">
    </div>
    
    <!-- Carousel -->
    <div class="list">
      <div class="listItem">
        <img src="https://placehold.co/100x100/000000/FFFFFF/png" alt="">
      </div>
      <div class="listItem">
        <img src="https://placehold.co/100x100/000000/FFFFFF/png" alt="">
      </div>
      <div class="listItem">
        <img src="https://placehold.co/100x100/000000/FFFFFF/png" alt="">
      </div>
    </div>
    Login or Signup to reply.
  3. I don’t think you need to toggle classes as others suggest if all you want to do is change some CSS, you can use the data attribute and value.

    Now, you want to add another one you don’t need to change code just add elements with the right values. As a bonus the new guys target selector can be anything that works AND even have different active style!

    let radioT = document.querySelectorAll("input[type='radio'][name='radio-btn']");
    
    function handleEventFun(event) {
      document.querySelectorAll('.listItem')
        .forEach(el => el.dataset.active = "false");
      let v = this.value;
      let radtarg = document.querySelector(v);
      radtarg.dataset.active = "true";
    
      /* this works but is a lot of code when you add conditions for all of them */
      /*
        let first = document.querySelector(".first");
        let second = document.querySelector(".second");
        let third = document.querySelector(".third");
        first.classList.toggle('activeRad',v ==='.first')
        first.classList.toggle('inactiveRad',v !=='.first')
        second.classList.remove("activeRad");
        third.classList.remove("activeRad");
        radtarg.classList.add("activeRad");
        ...need more code to handle it all
        */
    }
    radioT.forEach(el => el.addEventListener('click', handleEventFun));
    /* works to start */
    
    .listItem[data-active] {
      background-color: yellow;
      border: orange solid 1px;
    }
    
    .listItem[data-active="true"] {
      background-color: blue;
      border: solid red 2px;
    }
    .listItem[data-active="true"][data-iam="newguy"] {
        border: double purple 2px;
        padding: 1em;
        filter: saturate(50%);
    }
    
    .listItem[data-active="false"] {
      background-color: orange;
    }
    <!-- Radio buttons -->
    <div class="radio-inputs">
      <input class="radio-button" type="radio" name="radio-btn" value=".first">
      <input class="radio-button" type="radio" name="radio-btn" value=".second">
      <input class="radio-button" type="radio" name="radio-btn" value=".third">
      <input class="radio-button" type="radio" name="radio-btn" value=".listItem[data-iam='newguy']">
    </div>
    
    <!-- Carousel -->
    <div class="list" data-slides>
      <div class="listItem first" data-active="true">
        <img src="https://placehold.co/100x100/000000/FFFFFF/png" alt="">
      </div>
      <div class="listItem second" data-active>
        <img src="https://placehold.co/100x100/000000/FFFFFF/png" alt="">
      </div>
      <div class="listItem third" data-active>
        <img src="https://placehold.co/100x100/000000/FFFFFF/png" alt="">
      </div>
      <div class="listItem" data-active data-iam="newguy">
        <img src="https://placehold.co/100x100/000000/FFFFFF/png" alt="">
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search