skip to Main Content

How do I hide previous option based on the data attribute of another option?

I’m generating timeslots with PHP and checking against my DB if a specific timeslot is already booked. If a timeslot is booked I add a data attribute to the specific option with a value indicating how many timeslots before this time slot that needs to be hidden.

The current output achieved:

<select class="form-control" id="selectTimeslot">
   <option value="18:00">18:00</option>
   <option value="18:30">18:30</option>
   <option value="19:00">19:00</option>
   <option disabled value="19:30" data-time="2">19:30</option>
   <option value="20:00">20:00</option>
</select>

As you’ve noticed some option‘s have a data-time attribute. The data-time value indicates how many timeslots need to be removed before this option to allow prep time for the kitchen on the booked order.

I would like to remove the total amount of option‘s before the data-time based on the data-time value.

For example if data-time = "2" I need to remove the 2 options before the option with the data-time attribute. If data-time = "3" remove three (3) options, etc.

Expected output:

<select class="form-control" id="selectTimeslot">
   <option value="18:00">18:00</option>
   <option value="19:30" data-time="2">19:30</option>
   <option value="20:00">20:00</option>
</select>

I know how to remove a specific option based on a specific value however I don’t know how to remove specific options based on a data attribute as there can be multiple option with different data attribute values.

I tried doing this with the nth-child() approach but struggling immensely.

Any assistance would greatly be appreciated.

3

Answers


  1. It would be much easier if your data could just output an array of times that should be removed. Right now to find the piece of data that has data about other data that needs to be removed is really overly-complex.

    If you could just have it output something like:

    var DISALLOWED_TIMES = ['18:30', '19:00'];
    

    If you did this, the code would work like this:

    //From Server
    var DISALLOWED_TIMES = ['18:30', '19:00'];
    
    //Code on page
    DISALLOWED_TIMES.forEach(v => {
       document.querySelector('#selectTimeslot option[value="' + v + '"]').remove()
    });
    <select class="form-control" id="selectTimeslot">
       <option value="18:00">18:00</option>
       <option value="18:30">18:30</option>
       <option value="19:00">19:00</option>
       <option disabled value="19:30">19:30</option>
       <option value="20:00">20:00</option>
    </select>

    However, that’s just my suggestion and not related to what you actually asked.


    Below is what I came up with to work how you have asked the question, but of course it is a bit more complicated. Basically we have to reverse-loop through all options until we find one with the data attribute, save that as a number, and then for the next N iterations of that reversed loop we remove elements and update the remaining number of items to remove. This is a lot more fragile than the above simpler code which is more explicit about exactly what needs to be removed.

    var options = document.querySelectorAll('#selectTimeslot option');
    
    var numLeftToRemove = 0;
    for(var i = options.length-1; i >= 0; i--){
      var opt = options[i];
      
      if(opt.hasAttribute('data-time')){
        numLeftToRemove = +opt.getAttribute('data-time');
      }
      
      if(numLeftToRemove > 0){
        opt.remove();
        numLeftToRemove--;
      }
    }
    <select class="form-control" id="selectTimeslot">
       <option value="18:00">18:00</option>
       <option value="18:30">18:30</option>
       <option value="19:00">19:00</option>
       <option disabled value="19:30" data-time="2">19:30</option>
       <option value="20:00">20:00</option>
    </select>
    Login or Signup to reply.
  2. Ideally you would do this serverside to 1) only provide valid available options to the client and 2) not require any processing by the client

    Although since you tagged jQuery, this would be pretty simple with prevAll() and slice():

    $('#selectTimeslot option[data-time]').each(function(index, option) {
      $(option).prevAll().slice(0, option.getAttribute('data-time')).remove();
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <select class="form-control" id="selectTimeslot">
       <option value="18:00">18:00</option>
       <option value="18:30">18:30</option>
       <option value="19:00">19:00</option>
       <option disabled value="19:30" data-time="2">19:30</option>
       <option value="20:00">20:00</option>
    </select>
    Login or Signup to reply.
  3. We can utilize selectedIndex with number of items needed to be hidden/disabled

    $("#selectTimeslot").on("change", function() {
      //Get the selected index
      var selectedIndex = this.selectedIndex;
      //Number of items to remove
      var itemsToRemove = $(this).find(":selected").data("time") ? $(this).find(":selected").data("time") : 0;
      //Reset the options
      var options = $(this).find("option");
      //options.prop("disabled", false);
      options.show();
    
      //Hide/Disavle the relative itmes
      if (itemsToRemove) {
        for (i = (selectedIndex - selectedIndex + 1); i < selectedIndex; i++) {
          //$(options[i]).prop("disabled", true);
          $(options[i]).hide();
        }
      }
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <select class="form-control" id="selectTimeslot">
      <option value="18:00">18:00</option>
      <option value="18:30">18:30</option>
      <option value="19:00">19:00</option>
      <option value="19:30" data-time="2">19:30</option>
      <option value="20:00">20:00</option>
    </select>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search