Search code examples
javascriptjqueryradio-buttonsettimeoutsetinterval

automatically loop through radio buttons but also be able to manually switch


I'm trying to iterate through radio buttons automatically every 5 seconds via jquery; however i need the function to also run when i manually switch buttons. Here's what I have so far:

$(document).ready(function () {
  
  (function news() {
    
    if ($('#pabnews_slide1').is(':checked')) {
      $('#pabnews_slide2').prop('checked', true)
    }
    else if ($('#pabnews_slide2').is(':checked')) {
      $('#pabnews_slide3').prop('checked', true)
    }
    else if ($('#pabnews_slide3').is(':checked')) {
      $('#pabnews_slide4').prop('checked', true)
    }
    else if ($('#pabnews_slide4').is(':checked')) {
      $('#pabnews_slide1').prop('checked', true)
    }
    
    setTimeout(news, 5000);
    
  })();
  
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<input name="slideshow" id="pabnews_slide1" type="radio" checked />
<label for="pabnews_slide1">A</label>
<input name="slideshow" id="pabnews_slide2" type="radio"/>
<label for="pabnews_slide2">B</label>
<input name="slideshow" id="pabnews_slide3" type="radio" />
<label for="pabnews_slide3">C</label>
<input name="slideshow" id="pabnews_slide4" type="radio" />
<label for="pabnews_slide4">D</label>

which works, but my issue is that the function is called every 5 secs and the timer does not go back to 0 when i manually switch buttons. How would you go about doing that?

To be clearer, in the current state, when you wait 3 seconds and manually switch button, the function is called only 2 seconds afterwards and I would need to make it 5.


Solution

  • Here is a vanilla JS example though I did add a dataset attribute to your HTML to track the number of the elements being changed and to use in selecting the changed element one would select. I also refactored the function that increments through the list of elements and changes the checked element.

    First we get the a list of the input elements using the name tag.

    Then we set an incrementer, i, to match the dateset and index of each element within a loop.

    Because we want to track which element is currently being selected and which element the setTimeout is on, we will track these with variables currentSlide and SelectedSlide. Then we instantiate an empty variable to track the timeout timer.

    Now we run logic in a function to change the element using the incrementer and the list of input elements, if i is greater than the list of elements length reset i to 0. Then we track the value of selectedSlide, if it is set, we set the value of i to its dataset.id.

    Now, keep in mind that selectedSlide is set within the method/function setCurrentSlide(e) which tracks the event.target being changed to. Within that function we run clearTimeout(timer) which clears the setTimeout() and we re-instantiate the timer passing in the selectedSlide element so we can get its dataset.id and use that to set the loop to the proper element to start at when we call the changeSlide() method/function.

    currentSlide is set using i on the list of elements slides => currentSlide = slides[i]

    Lastly, we use the list of elements slides to run an eventListener that listens for a change event. Here we call the set setCurrentSlide method/function, which again uses the event.target => e.target to retrieve the dataset.id. Then we set that elements checked attribute to true.

    We then set the value of timer using a setTimeout(), passing in the changeSlide function and setting its delay.

    Lastly we increment i by 1, i++.

    Let me know if anything is not making sense and I hope this helps out. I left notes within the code to help understand what each line is doing.

    $(document).ready(function() {
      // get all the slides elements
      const slides = document.querySelectorAll('input[name="slideshow"]');
      // set an incrementer
      let i = 0;
      // instantiate empty variables
      var currentSlide, selectedSlide, timer;
      
      // method to changeEach slide to the next in line and reset to
      function changeSlide(currentSlide, selectedSlide){
        // ternary conditional, sets i to 0 if it has reached the last element
        i > slides.length-1 ? i = 0 : null;
        // ternary conditional, sets the selectedSlide if it is passed as a param
        selectedSlide ? i = selectedSlide.dataset.id : null;
        // set the current element to the indexed incrementer
        currentSlide = slides[i];
        // checks the proper element using the checked attribute
        currentSlide.checked = true; 
        // define timer and call the changeSlide method and set delay
        timer = setTimeout(changeSlide, 5000);
        // increment i by 1
        i++;   
      }
      
      // method to set current element 
      // uses the eventTarget passed from the eventListener
      function setCurrentSlide(e){
        // clear the timeout
        clearTimeout(timer);
        // set the selectedSlide variable to the event.target
        selectedSlide = e.target;
        // run the changeSlide method again using the event.target as reference as selectedSlide param
        changeSlide(currentSlide, selectedSlide);
      }
      
      // iterate over the slides elements
      slides.forEach(slide => {
        // event listener listens for a change and runs the setCurrentSlide method
        slide.addEventListener('change', setCurrentSlide);
      });
      
      // run the changeSlide method
      changeSlide(currentSlide, selectedSlide);
    
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <input name="slideshow" id="pabnews_slide1" data-id="0" type="radio" checked />
    <label for="pabnews_slide1">A</label>
    <input name="slideshow" id="pabnews_slide2" data-id="1" type="radio" />
    <label for="pabnews_slide2">B</label>
    <input name="slideshow" id="pabnews_slide3" data-id="2" type="radio" />
    <label for="pabnews_slide3">C</label>
    <input name="slideshow" id="pabnews_slide4" data-id="3" type="radio" />
    <label for="pabnews_slide4">D</label>