user3844782 user3844782 - 17 days ago 5
AngularJS Question

Bootstrap DateTimePicker with AngularJS: Passing directive ngModel value to controller

I am trying to get angular bootstrap datetimepicker input value using a custom directive like shown below. I am able to get the value in directive. How can i access this directive scope value in angular controller.

HTML

<div class='input-group date' id='datetimepickerId' datetimez ng-model="dueDate" >
<input type='text' class="form-control" />
</div>


Controller

App.directive('datetimez', function(){
return {
require: '?ngModel',
restrict: 'A',
link: function(scope, element, attrs, ngModel){
if(!ngModel) return;
ngModel.$render = function(){
element.find('#datetimepickerId').val( ngModel.$viewValue || '' );
};
element.datetimepicker({
format : 'YYYY-MM-DD HH:mm:ss'
});
element.on('dp.change', function(){
scope.$apply(read);
});
read();
function read() {
var value = element.find('#datetimepickerId').val();
ngModel.$setViewValue(value);
console.log(scope.dueDate);
}
}
};
});

App.controller('myController', ['$scope', function($scope) {
console.log($scope.dueDate);
}]);


Log inside the directive prints value successfully. But log inside controller does not.

Answer

Here you go.

I checked the documentation of the bootstrap datetimepicker and come to know there are two implementation.

  1. One with a icon to click and show the datetimepicker
  2. Another one just with a textbox without a icon

For the first one, you have to use the parent div to initiate the plugin and for the second option, you have to use the textbox to initiate the plugin

You have used the second option but used the parent div to initiate the plugin with a directive.

Also, div elements won't support the ngModel, hence directive should be used with the input element.

I have extended your directive to handle both scenarios and also the date format and other options can be passed from the controller.

You can give a try with the below working snippet.

var App = angular.module('App', []);

App.directive('datetimez', function(){
    return {
        require: '?ngModel',
        restrict: 'A',
        link: function(scope, element, attrs, ngModel){
            if(!ngModel) return;  
          
            ngModel.$render = function(){
                element.val( ngModel.$viewValue || '' );
            };
          
            function read() {
                var value = element.val();
                ngModel.$setViewValue(value);
                //console.log(scope.dueDate);
            }
            
            var options = scope.$eval(attrs.datetimez) || {};
            if(element.next().is('.input-group-addon')) {
              var parentElm = $(element).parent();
              parentElm.datetimepicker(options);
          
              parentElm.on('dp.change', function(){
                 scope.$apply(read);
              });
            } else {
              element.datetimepicker(options);
          
              element.on('dp.change', function(){
                 scope.$apply(read);
              });
            }
          
            read();
        }
    };
});

App.controller('myController', ['$scope', function($scope) {
  
    $scope.datePickerOptions = { 
       format : 'YYYY-MM-DD HH:mm:ss'
    };
    
    $scope.$watch('dueDate1', function(){
      console.log($scope.dueDate1);
    });
  
    $scope.$watch('dueDate2', function(){
      console.log($scope.dueDate2);
    });
}]);

angular.bootstrap(document, ['App']);
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.43/css/bootstrap-datetimepicker.min.css" rel="stylesheet"/>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.16.0/moment.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.43/js/bootstrap-datetimepicker.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>


<div class="container" ng-controller="myController">
    
    <div class="row">
        <div class='col-md-6'>
            <div class="form-group">
                <div class='input-group date' id='datetimepicker1'>
                    <input type='text' class="form-control" datetimez="datePickerOptions" ng-model="dueDate1" />
                </div>
            </div>
        </div>
    </div>
  
    <div class="row">
        <div class='col-md-6'>
            <div class="form-group">
                <div class='input-group date' id='datetimepicker1'>
                    <input type='text' class="form-control" datetimez="datePickerOptions" ng-model="dueDate2" />
                    <span class="input-group-addon">
                        <span class="glyphicon glyphicon-calendar"></span>
                    </span>
                </div>
            </div>
        </div>
    </div>
</div>