Search code examples
javascripthtmljquery-selectors

How do I run the code in a loop until a click has been performed?


I'm trying to book a vaccine in my country. This code applies the filters and then clicks a slot if vaccines are available.

The first 3 lines select the filters and the last line clicks on an available slot.

document.querySelector('.pin-search-btn.district-search.md.button.button-solid.ion-activatable.ion-focusable.hydrated').click()
setTimeout(() => {
  document.querySelector('#c1').click()
}, 1000);
setTimeout(() => {
  document.querySelector('#c5').click()
  document.querySelectorAll('.vaccine-box').forEach(function(item) {
    if (item.getElementsByTagName('a')[0].innerHTML !== ' Booked ' && item.getElementsByTagName('a')[0].innerHTML !== ' NA ') {
      item.getElementsByTagName('a')[0].click()
    }
  })
}, 2000);
<-- html needed -->

I want to run this code in a loop over a 2 second time interval until the final click has been performed. item.getElementsByTagName('a')[0].click()

P.S : I'm running this in Developer Tools on Chrome, I don't know if that info is relevant here or not.


Solution

  • Intuitively, I would suggest keeping a boolean hasClickedSlot = false, which you update once a slot has been clicked. Before calling setTimeout for 2 more seconds, ensure that !hasClickedSlot still holds.

    That could look something like:

    let hasClickedSlot = false;
    
    function clickButton() {
      document.querySelector('.pin-search-btn.district-search.md.button.button-solid.ion-activatable.ion-focusable.hydrated').click();
      
      // after 1 second, click on the C1 button
      setTimeout(clickC1, 1000);
    }
    
    function clickC1() {
      document.querySelector('#c1').click();
      
      // after 2 seconds, try to click on a slot
      setTimeout(tryClickSlot, 2000);
    }
    
    
    function tryClickSlot() {
      document.querySelector('#c5').click();
      document.querySelectorAll('.vaccine-box').forEach(function(item) {
        if (item.getElementsByTagName('a')[0].innerHTML !== ' Booked ' && item.getElementsByTagName('a')[0].innerHTML !== ' NA ') {
          item.getElementsByTagName('a')[0].click()
          hasClickedSlot = true;
        }
      });
    
      // if no slot was clicked yet, do it again
      if (!hasClickedSlot) {
        clickButton();
      }
    }
    
    // start the process
    clickButton();
    
    

    The disadvantage of this code specifically is that a stack of calls is built, as the functions do not return but rather keep stacking.

    Edit: Since the functions return after calling setTimeout no stack call is built (as it would during recursion, for instance).