Bootstrap Datetimepicker more than one set of related pickers per page
I am using Eonasdan Bootstrap Datetimepicker https://eonasdan.github.io/bootstrap-datetimepicker/#linked-pickers and am trying to set up linked pickers.
I can get it to work as needed if I have one pair of collectors per page, but not if I have multiple pairs - I use classes to target collectors, so I guess my problem is with the way dp. change is run.
The code looks something like this:
<form>
<div class="container">
<div class="row">
<div class="col-md-6">
<input type="text" name="start" class="dp">
</div>
<div class="col-md-6">
<input type="text" name="end" class="dp2">
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-6">
<input type="text" name="start" class="dp">
</div>
<div class="col-md-6">
<input type="text" name="end" class="dp2">
</div>
</div>
</div>
</form>
JS:
$('.dp').datetimepicker({
showTodayButton: true,
showClose: true,
toolbarPlacement: "bottom",
format: "DD/MM/YYYY",
widgetPositioning: {
vertical: 'bottom',
horizontal: 'left'
}
}).on('dp.change',function(e){
$('.dp2').data("DateTimePicker").minDate(e.date);
});
$('.dp2').datetimepicker({
showTodayButton: true,
showClose: true,
toolbarPlacement: "bottom",
useCurrent: false,
format: "DD/MM/YYYY",
widgetPositioning: {
vertical: 'bottom',
horizontal: 'left'
}
}).on('dp.change',function(e){
$('.dp').data("DateTimePicker").maxDate(e.date);
});
The first time pickers appear on the page, they work as expected - date 1 is given, and picker for date 2 has a minimum date value of 1, and no earlier dates can be selected.
The second time the collector appears, it is not referenced correctly - the collectors are still running, etc., but they are not linked.
Due to the dynamic nature of the system in which this is used, I cannot use the ID for target pickers as I could have 1 pair or 20 pairs.
Is there a way for the second and subsequent collectors to bind correctly?
source to share
You need to choose 'dp'
and 'dp2'
which have the closest sibling relationship . ei: have the same great parent , in this case 'row'
. Right now, the first 'dp'
or will always be selected 'dp2'
.
Here's how you can do it:
Instead:
$('.dp2').data("DateTimePicker").minDate(e.date);
You should have something like:
$(this).parents('.row')
.find('.dp2')
.data("DateTimePicker")
.minDate(e.date);
This way you only target "dp2" which is linked to "dp" and vice versa. The complete js code might look something like this:
$('.dp').datetimepicker({
showTodayButton: true,
showClose: true,
toolbarPlacement: "bottom",
format: "DD/MM/YYYY",
widgetPositioning: {
vertical: 'bottom',
horizontal: 'left'
}
}).on('dp.change',function(e){
$(this).parents('.row')
.find('.dp2')
.data("DateTimePicker")
.minDate(e.date);
});
$('.dp2').datetimepicker({
showTodayButton: true,
showClose: true,
toolbarPlacement: "bottom",
useCurrent: false,
format: "DD/MM/YYYY",
widgetPositioning: {
vertical: 'bottom',
horizontal: 'left'
}
}).on('dp.change',function(e){
$(this).parents('.row')
.find('.dp')
.data("DateTimePicker")
.maxDate(e.date);
});
source to share
Your jQuery selectors always only find the first instance of .dp
/ .dp2
. If we wrap each date range in a class .date-range
(at the level .row
), we can then search for the start and end date fields in that context:
$(".date-range").each(function(index, range) {
var $from = $(range).find(".dp").first();
var $to = $(range).find(".dp2").first();
$from.datetimepicker({
showTodayButton: true,
showClose: true,
toolbarPlacement: "bottom",
format: "DD/MM/YYYY",
widgetPositioning: {
vertical: 'bottom',
horizontal: 'left'
}
}).on('dp.change', function(e) {
$to.data("DateTimePicker").minDate(e.date);
})
.prop('type', 'text')
.bind({
blur: function(ev) {
Form.Options.Validate.onkeyup($(this), ev);
}
});
$to.datetimepicker({
showTodayButton: true,
showClose: true,
toolbarPlacement: "bottom",
useCurrent: false,
format: "DD/MM/YYYY",
widgetPositioning: {
vertical: 'bottom',
horizontal: 'left'
}
}).on('dp.change', function(e) {
$from.data("DateTimePicker").maxDate(e.date);
})
.prop('type', 'text')
.bind({
blur: function(ev) {
Form.Options.Validate.onkeyup($(this), ev);
}
});
});
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/3.1.2/css/bootstrap-datetimepicker.min.css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.min.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/js/bootstrap.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>
<form>
<div class="container">
<div class="row date-range">
<div class="col-md-6">
<input type="text" name="start" class="dp">
</div>
<div class="col-md-6">
<input type="text" name="end" class="dp2">
</div>
</div>
</div>
<div class="container">
<div class="row date-range">
<div class="col-md-6">
<input type="text" name="start" class="dp">
</div>
<div class="col-md-6">
<input type="text" name="end" class="dp2">
</div>
</div>
</div>
</form>
source to share