toffler
toffler

Reputation: 1233

Custom timepicker with jQuery and bootstrap

I build a custom timepicker with jQuery and bootstrap. It's almost finished, but 1 "nice to have detail" is missing and I'm stucked getting to the result.

It should follow this rules:

  1. Select the time on click
  2. Only related times are possible to select.
  3. Only 1 time range at once is possible (e.g. 09:00-11:00 works but can't pick another time range)
  4. Disabled times are not possible to pick and if they are between a possible time range, only the range before or after disabled are allowed.
  5. It should be possible to click the start time and the end time and if there are no obstacles in between, the times between should be selected as well.

1-4 are working but I'm stucked on point 5.

So what I want to achieve is that if I click on 13:00-14:00 and 15:00-16:00, 14:00-15:00 should be selected automatically if allowed by above rules.

    $('.time-cal .time-btn').on('click',function(){
        if($('.time-cal .time-btn.btn-success').length == 0)
        {
            $(this).not(".btn-danger").toggleClass('btn-success');
            $(this).not(".btn-danger").toggleClass('btn-light');
        }else{
            if($(this).hasClass('btn-light'))
            {
                if($(this).next().hasClass('btn-success') || $(this).prev().hasClass('btn-success'))
                {
                    $(this).not(".btn-danger").toggleClass('btn-success');
                    $(this).not(".btn-danger").toggleClass('btn-light');
                }
            }else{
                let next = $(this).next();
                let prev = $(this).prev();
                
                if(!next.hasClass('btn-success') || ! prev.hasClass('btn-success'))
                {
                    $(this).not(".btn-danger").toggleClass('btn-success');
                    $(this).not(".btn-danger").toggleClass('btn-light');
                }
            }
        }
    });
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

<div class="time-cal col-lg-6 col-12">
                                <label>Pick times</label><br>
                                <button type="button" class="btn btn-xs time-btn btn-danger" data-start="07:00" data-end="08:00" disabled="">07:00 - 08:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-danger" data-start="08:00" data-end="09:00" disabled="">08:00 - 09:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="09:00" data-end="10:00">09:00 - 10:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="10:00" data-end="11:00">10:00 - 11:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-danger" data-start="11:00" data-end="12:00" disabled="">11:00 - 12:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="12:00" data-end="13:00">12:00 - 13:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="13:00" data-end="14:00">13:00 - 14:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="14:00" data-end="15:00">14:00 - 15:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="15:00" data-end="16:00">15:00 - 16:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-danger" data-start="16:00" data-end="17:00" disabled="">16:00 - 17:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-danger" data-start="17:00" data-end="18:00" disabled="">17:00 - 18:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="18:00" data-end="19:00">18:00 - 19:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="19:00" data-end="20:00">19:00 - 20:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="20:00" data-end="21:00">20:00 - 21:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="21:00" data-end="22:00">21:00 - 22:00</button>

                                <div class="form-group">

                                </div>  
                            </div>
                            
                            <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
                            <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

Upvotes: 1

Views: 200

Answers (1)

Me.Name
Me.Name

Reputation: 12544

-edit altered behaviour based on the comments. At startup each time'button' is divided into a specific timeblock so buttons in the same timeblock can be quickly handled together (there might be some additional/other behavioral requirements when reselecting)

const 
        disabledClass = 'btn-danger',
    selectedClass = 'btn-success',
    notselectedClass = 'btn-light',        
    timeButtons = $('.time-cal .time-btn'),
    enabledButtons = timeButtons.not('.' + disabledClass ),
    timeBlocks = [];    
    
    timeButtons.each((index,btn)=>{btn.enabled=!$(btn).hasClass(disabledClass); 
        if(btn.enabled){
        if(index===0 || !timeButtons[index-1].enabled){         
          timeBlocks.push([]); //new timeblock
        }
        btn.timeBlock = timeBlocks[timeBlocks.length-1];
        btn.timeBlock.push(btn);
      }
      prevEnabled = btn.enabled;
        btn.index = index;btn.selected=false;       
      btn.setSelected = sel => {if(btn.selected===sel)return; btn.selected=sel;
            $(btn).toggleClass(notselectedClass,!sel).toggleClass(selectedClass,sel);}
      });
    

         
enabledButtons.click(function(){          
         if(this.selected){
                //deselect and make sure times in this block after this button are deselected too
                        this.timeBlock.filter(btn=>btn.index >= this.index && btn.selected).forEach(btn=>btn.setSelected(false));
            return;
         }
                
        //deselect other timeblocks
        enabledButtons.toArray().filter(b=>b.timeBlock !== this.timeBlock).forEach(b=>b.setSelected(false));
        
        //check if there are other selected
        const selected = this.timeBlock.filter(b=>b.selected);
        if(selected.length === 0)
          this.setSelected(true); //no other buttons selected, simply select
        else{
          //select range withint the timeblock
          let from = selected[0].index, to = this.index;
          if(from > to)
            [from,to] = [to,from];
          for(let i = from;i<=to;i++)
            timeButtons[i].setSelected(true);
        }       
        
    });
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

<div class="time-cal col-lg-6 col-12">
                                <label>Pick times</label><br>
                                <button type="button" class="btn btn-xs time-btn btn-danger" data-start="07:00" data-end="08:00" disabled="">07:00 - 08:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-danger" data-start="08:00" data-end="09:00" disabled="">08:00 - 09:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="09:00" data-end="10:00">09:00 - 10:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="10:00" data-end="11:00">10:00 - 11:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-danger" data-start="11:00" data-end="12:00" disabled="">11:00 - 12:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="12:00" data-end="13:00">12:00 - 13:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="13:00" data-end="14:00">13:00 - 14:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="14:00" data-end="15:00">14:00 - 15:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="15:00" data-end="16:00">15:00 - 16:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-danger" data-start="16:00" data-end="17:00" disabled="">16:00 - 17:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-danger" data-start="17:00" data-end="18:00" disabled="">17:00 - 18:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="18:00" data-end="19:00">18:00 - 19:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="19:00" data-end="20:00">19:00 - 20:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="20:00" data-end="21:00">20:00 - 21:00</button>
                                <button type="button" class="btn btn-xs time-btn btn-light" data-start="21:00" data-end="22:00">21:00 - 22:00</button>

                                <div class="form-group">

                                </div>  
                            </div>
                            
                            <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
                            <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

Upvotes: 1

Related Questions