I've been trying to figure this out for a few days now and I think it's time to turn to you fine folks. Ok I'm building a calendar app that's using Angular + datepair/datepicker/timepicker. I have a start time field and an end time field. It would be nice if a user cannot pick choose an end time that occurs before the start time. On the Timepicker website the very last example is exactly what I'm trying to do but I can't seem to get it to work with Angular.
Here's the example that was on timepicker's site:
<p id="datepairExample">
<input type="text" class="date start" />
<input type="text" class="time start" /> to
<input type="text" class="time end" />
<input type="text" class="date end" />
</p>
<script type="text/javascript" src="jquery.datepair.js"></script>
<script>
// initialize input widgets first
$('#datepairExample .time').timepicker({
'showDuration': true,
'timeFormat': 'g:ia'
});
$('#datepairExample .date').datepicker({
'format': 'yyyy-m-d',
'autoclose': true
});
// initialize datepair
$('#datepairExample').datepair();
</script>
Here's my code.
Angular directives:
viasam.directive('datepicker', function(){
return {
restrict: 'A',
link: function ($scope, $element) {
$element.datepicker({
format: 'd/m/yyyy',
autoclose: true,
todayHighlight: true
});
}
}
});
viasam.directive('timepicker', function(){
return {
restrict: 'A',
link: function ($scope, $element) {
$element.timepicker({
'minTime': '8:00am',
'maxTime': '8:00pm',
'timeFormat': 'g:i A',
'showDuration': true,
'scrollDefaultNow': true
});
}
}
});
viasam.directive('datepair', function(){
return {
restrict: 'A',
link: function ($scope, $element) {
$element.datepair({
'defaultDateDelta': 0,
'defaultTimeDelta': 7200000
});
}
}
});
The form:
<div id="datepair">
<%= form_tag blocks_create_es_path, :class => "form-horizontal" do %>
<div datepair>
<%= text_field_tag(:start_day, nil, class: 'date start datepicker form-control input-sm', :datepicker => 'datepicker') %>
<%= text_field_tag(:start_hour_and_minute, nil, class: 'start form-control input-sm', :timepicker => 'timepicker') %>
<%= text_field_tag(:end_hour_and_minute, nil, class: 'end form-control input-sm', :timepicker => 'timepicker') %>
<%= text_field_tag(:end_day, nil, class: 'date end datepicker form-control input-sm', :datepicker => 'datepicker') %>
<%= submit_tag "Abrir bloque de tiempo" %>
</div>
<% end %>
</div>
Here's what I did. This is my timepicker directive:
.directive('timePicker', ['$timeout', function ($timeout) {
return {
restrict: 'AC',
scope: {
ngModel: '='
},
link: function (scope, element) {
element.on('change', function () {
if (element.hasClass('start')) {
$timeout(function () {
var $el = element.closest('[date-pair]').find('input.end'),
endScope = angular.element($el).isolateScope();
endScope.$apply(function () {
endScope.ngModel = $el.val();
});
}, 0);
}
});
element.timepicker({
timeFormat: 'H:i',
forceRoundTime: true
});
}
};
}]);
And my datePair directive is pretty similar to yours:
.directive('datePair', [function () {
restrict: 'AC',
link: function (scope, element) {
element.datepair();
}
}]);
Your HTML could look something like this:
<div date-pair>
<input time-picker class="time start" ng-model="something.start">
<input time-picker class="time end" ng-model="something.end">
</div>
You could still use your date-pair directive, but do note that I added a hyphen in my attribute.
What happens is that when the change
event is triggered in a start timePicker, it'll update the scope for the end timePicker to reflect the change made by the jQuery plugin.
It's not too fast though, it usually updates within a second (less than a second most of the time)