5

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?

3
  • its a different library, works differently. not duplicate. Commented May 20, 2015 at 18:20
  • Updated an answer to reflect boostrap 3's event, instead of jQuery UI Commented May 20, 2015 at 18:22
  • I'm having a problem that the ng-model property on my viewmodel is not updated when I pick a date from the calendar (without actively write anything on the textbox), and it remains with the angular directive ng-pristine because it never refreshes with the new selected value. Anything to take into consideration? Commented Jun 15, 2015 at 13:02

6 Answers 6

4

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" />
Sign up to request clarification or add additional context in comments.

Comments

3

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;

            });

        }

Comments

1

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
                            });
                          }
                        };
                      });

Comments

1

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'
    });
})();

Comments

0

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>`
        })

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.