Blaze + Bootstrap 4 Modal + Daterangepicker


#1

After several attempts, I have been able to get daterangepicker to show up in bootstrap 4 modal, but not without the weird behavior of only showing up after the modal has been closed and opened again. It never shows up on first open of the modal.

the modal is a partial activated by this call

 'click #laucnhdateRangeModal': function(e,t) {
         $('#dateRangeModal').modal('show');
         $('input[name="birthday"]').daterangepicker({ parentEl: $('#dateRangeModal'), showDropdowns: true});
 },

challenge is when the modal is rendered, the daterangepicker doesn’t show unless the modal is closed and opened again.
Does anyone have an idea whats happening?


#2

Your question doesn’t seem really Blaze related, as you are just using jQuery and Bootstrap inside a single function, and since I don’t actually have first-hand experience on Bootstrap since 2014, I’m just guessing.

First thing I’d fix is the typo on…

…and double check you have the same type of mixed casing used in the actual template. It’s probably not the reason for the weird behavior though, so based on your description I’d probably make sure that this input[name="birthday"] actually exists when you are trying to initialize this Bootstrap sorcery on it. If it hasn’t been for example yet rendered or mounter on DOM, you could try

Tracker.afterFlush(() => $('input[name="birthday"]').daterangepicker({ parentEl: $('#dateRangeModal'), showDropdowns: true}));

…or maybe check, if modal('show') has a callback mechanism to inform you when the modal has been succesfully rendered.

If you could provide the template code as well, it might be easier to help.


#3

main template partial html;

<template name="scheduleEventFormPartial">
        <div id="collapseSecond" class="collapse" data-parent="#accordion">
            <div class="card-body text-left">
                <div class="row">
                    <div class="col-xs-12">
                            {{> dateRangeModal}}
                            {{> timeZoneModal}} 
                           <p>launch daterange modal <a id="launchdateRangeModal" > Launch</a></p>                            
                    </div>
                </div>
            </div>
            <div class="card-footer text-muted text-right">
               <a href="" >Cancel</a>  
               <button type="submit" class="btn btn-success">Save</button>
            </div>
        </div>	
</template>

main template partial js

Template.scheduleEventFormPartial.events({      
    'click #launchdateRangeModal': function(e,t) {
        // currentEventName.set(e.target.value);
        $('#dateRangeModal').modal('show');
        $('input[name="birthday"]').daterangepicker({ parentEl: $('#dateRangeModal'), showDropdowns: true});
    },
});

modal html

<template name="dateRangeModal">
      <!-- Modal -->
      <div class="modal fade" id="dateRangeModal" tabindex="-1" role="dialog" aria-labelledby="dateRangeModalTitle" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered" role="document">
          <div class="modal-content">
            <!-- <div class="modal-header">
              <h5 class="modal-title" id="exampleModalLongTitle">Modal title</h5>
              <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true">&times;</span>
              </button>
            </div> -->
            <div class="modal-body">
              <h5 class="modal-title" id="exampleModalLongTitle">Availability</h5>
              {{#if equals currentDateRangeType "DateRange"}}        
                  show calendar
                  <input type="text" name="birthday" value="" />
                </p>
              {{/if}}            
            </div>
            
            <div class="modal-footer">
              <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
              <!-- <button type="button" class="btn btn-primary">Apply</button> -->
            </div>
          </div>
        </div>
      </div> 
</template>

modal js

Template.dateRangeModal.onCreated(function dateRangeModalOnCreated() {
     let template = Template.instance();   
     console.log("date range modal created")
//     $('#dateRangeModal').on('shown.bs.modal', function() {
//         $('input:text:visible:first').focus();
//         // prepare datepicker
//         $('input[name="birthday"]').daterangepicker({
//              singleDatePicker: true,
//              showDropdowns: true,
//              parentEl: $('#dateRangeModal')   
//         });
//    });

    // $('input[name="birthday"]').daterangepicker({ parentEl: $('#dateRangeModal'), showDropdowns: true,});

});

Template.dateRangeModal.onRendered(function dateRangeModalOnRendered() {
    console.log("daterange modal rendered")
//     $('#dateRangeModal').on('shown.bs.modal', function() {
//         $('input:text:visible:first').focus();
//         // prepare datepicker
//         $('input[name="birthday"]').daterangepicker({
//              singleDatePicker: true,
//              showDropdowns: true,
//              parentEl: $('#dateRangeModal')   
//         });
//    });
});
  
Template.dateRangeModal.helpers({ 
   
});
  
Template.dateRangeModal.events({ 
    
});

upon further troubleshooting, I realise conole.log in modals for bot created and rendered all show up long before the modal linked is actually clicked for modal to even show up. Could this be a sourcce as well? why should those consoles run when modal has not yet been activated?


#4

Few notes:

Wait for “shown.bs.modal”

I don’t use Bootstrap, but in their documentation about the modal component, the first block of example code is this:

$('#myModal').on('shown.bs.modal', function () {
  $('#myInput').trigger('focus')
})

It’s probably a good idea to interact with the modal only once it’s been shown, something like this:

 'click #laucnhdateRangeModal'(e,t) {
      $('#dateRangeModal').on('shown.bs.modal', function () {
         $('input[name="birthday"]').daterangepicker({ parentEl: $('#dateRangeModal'), showDropdowns: true});
      });
      $('#dateRangeModal').modal('show');
 },

Follow the daterangepicker API

In the DateRangePicker documentation the parentEl prop is defined as a string, a selector. You are passing down a jQuery object.

  • parentEl : (string) jQuery selector of the parent element that the date range picker will be added to, if not provided this will be ‘body’

So change that to:

$('input[name="birthday"]').daterangepicker({ parentEl: '#dateRangeModal', showDropdowns: true});

Beware of “if” clauses in templates and template inclusions when your third party code is operating “across template borders”

Your scheduleEventFormPartial is trying to trigger the modal using a DOM element that’s defined in it’s child template, dateRangeModal.

Also the input element you are trying to use as the base for DateRangePicker is behind an if -clause:

{{#if equals currentDateRangeType "DateRange"}}        
       show calendar
       <input type="text" name="birthday" value="" />
</p>
{{/if}}

Are you sure those elements exist in DOM when you are trying to manipulate them from the parent element?

(…and there is also some dangling </p> closing tag in there…? I don’t think this should even compile.)

Regarding the console.logs

You include the dateRangeModal-component directly in the parent template, so it should be created and rendered immediately. Clicking the #launchdateRangeModal link only triggers the jQuery-Bootstrap-sorcery on the specified DOM elements.

I recommend you refactor your code so that any Bootstrap-initializations happen inside the same template/component’s onRendered function where the target element(s) reside(s).

Hope these help!