2

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.

11
  • on line number 20 in js $scope.dueDate forgot $ symbol. Commented Nov 21, 2016 at 13:06
  • If i do that it says $scope is not defined Commented Nov 21, 2016 at 13:08
  • datetimez ng-model="dueDate" why are you using this in div tag instead of using in input ? Commented Nov 21, 2016 at 13:19
  • Is the controller, the directive's controller, or just a page (unrelated) controller? Commented Nov 21, 2016 at 13:19
  • 1
    when the controller is initialised there is no value in $scope.dueDate. Add ng-change in input and console in a function which is called on date change. Commented Nov 21, 2016 at 14:07

1 Answer 1

3

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>

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the great post. Will check now and get back soon.
i used this , but element.next(...).is is not a function error occured.