Search code examples
angularjsangular-uiangular-ui-bootstrapangular-ui-datepicker

Detect the selected month in Angular UI bootstrap datepicker


I'm using the Angular UI Bootstrap datepicker in day mode for my project. How can I get the currently open month befoure the new date was selected?


Solution

  • After spending some time trying to find the right way to get this, and upon reading the datepicker directive and controller's source code, I couldn't find a non-dirty way of getting the current month, so here's a very hacky way to do it.

    Warning, future versions of Angular-UI Bootstrap might break this approach

    You will need to use AngularJS decorators for this. Here's the code you'll need:

    angular.module('myApp', [
      'ui.bootstrap'
      ])
      .config(function($provide) {
        $provide.decorator('datepickerDirective', function($delegate) {
          var directive = $delegate[0];
          //get a copy of the directive's original compile function
          var directiveCompile = directive.compile;
    
          //overwrite the original compile function
          directive.compile = function(tElement, tAttrs) {
            // call the directive's compile with apply to send the original 'this' and arguments to it
            var link = directiveCompile.apply(this, arguments);
    
            //here's where the magic starts
            return function(scope, element, attrs, ctrls) {
              //call the original link
              link.apply(this, arguments);
              //move is the internal function called when you click
              //on the chevrons for previous and next month
              var originalMove = scope.move;
              scope.move = function(direction) {
                originalMove.apply(this, arguments);
                //when move is called, the 'this' object contains a 'title' property with the current month!
                var currentMonth = this.title;
                //emit the event to parent scopes
                scope.$emit('datepicker.monthChanged', currentMonth);
              }
            }
          };
    
          return $delegate;
        });
      })
    

    And then your controller can listen to datepicker.monthChanged:

    $scope.$on('datepicker.monthChanged', function(event, newVal) {
      $scope.currentMonth = newVal;
    })
    

    Since the datepicker controller doesn't keep the current selected date within the $scope, it keeps it in a closure variable, the only way I found you could get the selected month was in the this object when the function move is called. move is called whenever you click on the previous and next month icons.

    Here's a plunkr demonstrating the usage of this decorator: http://plnkr.co/edit/iWJWjM8nCsh5TMupNioo?p=preview