Reputation: 62674
I am using this datetime picker in angular.
https://eonasdan.github.io/bootstrap-datetimepicker/
Inside of a controller I have:
$('#picker').datetimepicker();
In my HTML I have:
<div id="#picker" >
<input type='text' style="font-size:10pt;" class="rptv-input" placeholder="Start Time" ng-model='adate' ng-change="datechange()" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
Everything is managed by a controller "AppController". The problem is, when I select a date on the calendar by click, it does not trigger any "change" event (in other words, datechange is not fired). If I do a watch on ng-model "adate", it also does not seem to trigger it. If I type in the text box, then the scope variable changes.
How can I detect changes on the text box if the user clicks on a date in the selector to change it?
Upvotes: 5
Views: 9922
Reputation: 1
I recently was having the same issue (detecting the datetimepicker change event within angularJS using the https://eonasdan.github.io/bootstrap-datetimepicker/) and what actually worked for me was the same idea of @Mark Pieszak but with some minor changes (I guess because of the pluging version). If you are using the version 4 of the pluging you need to use the on listener and the dp.change event to get the change event
app.directive('datetimepicker', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
element.datetimepicker({
defaultDate: new Date(),
maxDate: moment().endOf('d'),
locale: 'es',
format: 'DD/MM/YYYY',
widgetPositioning: { horizontal: 'right', vertical: 'bottom' }
}).on('dp.change', function (date) {
scope.$apply(function () {
ngModelCtrl.$setViewValue(date.date !== false ? date : null);
});
});
}
}
});
and the usage is the same.
<input datetimepicker name="yourInputName" id="yourInputName" type='text' class="form-control" ng-model="yourModelProperty" ng-required="yourRequiredExpression" ng-disabled="yourDisabledExpression" />
The expression i used as the ngModelCtrl.$setViewValue() parameter was because when i only passed the date parameter the input was getting valid even when i left it blank.
Upvotes: 0
Reputation: 1261
For a global solution for your app, I definitely support the custom directives as shown in the answers above. But for one-offs:
According to the current Bootstrap documentation, the attached event handler needs to be looking for the changeDate event. See example:
Html Markup:
<input class="date-picker" type="text" ng-model="$ctrl.model.date" />
Angular 1.5.9 Controller:
(function () {
'use strict'
var MyTestController = function () {
var vm = this;
vm.model = {
date: undefined
};
(function initilize() {
$('.date-picker').datepicker({
autoclose: true,
forceParse: false
}).on('changeDate', function (e) {
console.log('date was changed to: ' + e.date);
});
})();
};
angular.module('myApp').component('myTest', {
controller: [MyTestController],
templateUrl: 'app/modules/my-test/view.html'
});
})();
Upvotes: 1
Reputation: 217
Another option would be
HTML:
<div class="input-group date" id="dateTimePicker">
<input type="text" class="form-control" />
<span class="input-group-addon" ng-click="setDateTime()">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
Controller:
$scope.setDateTime = function () {
$("#dateTimePicker").datetimepicker().on("dp.change", function (data) {
$scope.date = data.date._d;
});
}
Upvotes: 3
Reputation: 1
My directive and angular 1.5 component
.directive('externalUpdate', ['$parse', function($parse) {
return {
link: function(scope, element, attrs){
var setterFunc = $parse(attrs.ngModel).assign;
var func = scope.$eval(attrs.externalUpdate);
func(element, function(value) {
scope.$apply(function() {
setterFunc(scope, value);
});
});
}
};
}])
.component('datebox', {
bindings: {
size: '@@?',
name: '@@',
text: '@@',
model: '=',
classes: '@@?',
disabled: '=?',
time: '<?'
},
controller: function() {
if (!this.size) {
this.col1 = '6';
this.col2 = '6';
} else {
var size = parseInt(this.size);
this.col1 = size.toString();
this.col2 = (12 - size).toString();
}
this.updateInput = function(element, setter) {
element.on("dp.change", function() { setter(element.val()); });
}
},
template: String.raw`
<div class="form-group">
<label ng-if="$ctrl.col1!='0'" for="{{::$ctrl.name}}" class="col-md-{{::$ctrl.col1}} control-label">{{::$ctrl.text}}</label>
<div class="col-md-{{::$ctrl.col2}}">
<input type="text" id="{{::$ctrl.name}}" ng-disabled="$ctrl.disabled"
class="form-control input-sm {{::$ctrl.classes}}"
ng-class="[{datepicker: $ctrl.time!=true},{datetimepicker: $ctrl.time==true}]"
ng-model="$ctrl.model" external-update="$ctrl.updateInput">
</div>
</div>`
})
.component('daterangebox', {
bindings: {
size: '@@?',
name: '@@',
text: '@@',
model: '=',
classes: '@@?',
disabled: '=?',
time: '<?'
},
controller: function() {
if (!this.model || typeof this.model !== 'object') {
this.model = {};
}
if (!this.size) {
this.col1 = '6';
this.col2 = '6';
} else {
var size = parseInt(this.size);
this.col1 = size.toString();
this.col2 = (12 - size).toString();
}
this.updateInput = function(element, setter) {
element.on("dp.change", function() { setter(element.val()); });
}
},
template: String.raw`
<div class="form-group">
<label ng-if="$ctrl.col1!='0'" for="{{::$ctrl.name}}" class="col-md-{{::$ctrl.col1}} control-label">{{::$ctrl.text}}</label>
<div class="col-md-{{::$ctrl.col2}}">
<div class="input-group">
<input type="text" id="{{::$ctrl.name}}" ng-disabled="$ctrl.disabled"
class="form-control input-sm {{::$ctrl.classes}}"
ng-class="[{datepicker: $ctrl.time!=true},{datetimepicker: $ctrl.time==true}]"
ng-model="$ctrl.model.start" external-update="$ctrl.updateInput">
<span class="input-group-addon input-sm">-</span>
<input type="text" ng-disabled="$ctrl.disabled"
class="form-control input-sm {{::$ctrl.classes}}"
ng-class="[{datepicker: $ctrl.time!=true},{datetimepicker: $ctrl.time==true}]"
ng-model="$ctrl.model.end" external-update="$ctrl.updateInput">
</div>
</div>
</div>`
})
Upvotes: 0
Reputation: 668
The change event is triggered within bootstrap, so you might need to create a custom directive for your timepicker in order to catch the change
event like so :
.directive('yourDirective', function(){
return{
require: '?ngModel',
restrict: 'A',
link: function (scope,element,attrs, ngModel){
if (!ngModel) return;
element.bind('change', function(e){
//triggered event if change
});
}
};
});
Upvotes: 1
Reputation: 67131
Here's the jist of the logic, but basically you need to make a directive that in turn creates the datetimepicker itself. Then within boostraps change()
function you must do a $apply()
which triggers a digest cycle and updates your model.
boostrap 3 datetimepicker event documentation
angular.module('yourApp')
.directive('datetimepicker', function () {
return {
restrict: 'A',
require : 'ngModel',
link : function (scope, element, attrs, ngModelCtrl) {
element.datetimepicker({
change:function (date) {
// Triggers a digest to update your model
scope.$apply(function () {
ngModelCtrl.$setViewValue(date);
});
}
});
}
}
});
Useage :
<input datetimepicker ng-model="adate" />
Upvotes: 4