Skip to content

Instantly share code, notes, and snippets.

@cgmartin
Last active May 21, 2018 21:42
Show Gist options
  • Save cgmartin/3daa01f910601ced9cd3 to your computer and use it in GitHub Desktop.
Save cgmartin/3daa01f910601ced9cd3 to your computer and use it in GitHub Desktop.
Send an event to refresh view of ui-bootstrap datepicker
/**
* Decorates the ui-bootstrap datepicker directive's controller to allow
* refreshing the datepicker view (and rerunning invalid dates function)
* upon an event trigger: `$scope.$broadcast('refreshDatepickers');`
*
* Works with inline and popup. Include this after `ui.bootstrap` js
*/
angular.module('ui.bootstrap.datepicker')
.config(function($provide) {
$provide.decorator('datepickerDirective', function($delegate) {
var directive = $delegate[0];
var link = directive.link;
directive.compile = function() {
return function(scope, element, attrs, ctrls) {
link.apply(this, arguments);
var datepickerCtrl = ctrls[0];
var ngModelCtrl = ctrls[1];
if (ngModelCtrl) {
// Listen for 'refreshDatepickers' event...
scope.$on('refreshDatepickers', function refreshView() {
datepickerCtrl.refreshView();
});
}
}
};
return $delegate;
});
});
@MadsMadsDk
Copy link

@extropianer
Did you ever find a none-flicker-solution to this issue? :)

@oomkoos
Copy link

oomkoos commented Jan 22, 2016

@spirau or anyone else using uib-datepicker and dynamic-locale ....
did you manage to get the uib-datepicker day names to also refresh?

@rknell
Copy link

rknell commented Apr 14, 2016

@MadsMadsDk

This works for me and doesn't flicker:

super hacky but this seems to work for me. Replace the function in datepicker. I tried using $timeout but it didn't like it.

Step 1. Change the signature to include a retry variable. Its just a placeholder to kill the infinite loop.

this.refreshView = function(retry) {

Step 2. Add this to the end of the function

if(!retry){
      setTimeout(function () {
        console.log("Refreshing view timeout");
        _this.refreshView(true);
        $scope.$apply();
      }, 1);
    }

Full Code:

this.refreshView = function(retry) {
    console.log("Refresh view");
    if (this.element) {
      $scope.selectedDt = null;
      this._refreshView();
      if ($scope.activeDt) {
        $scope.activeDateId = $scope.activeDt.uid;
      }

      var date = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null;
      date = dateParser.fromTimezone(date, ngModelOptions.timezone);
      ngModelCtrl.$setValidity('dateDisabled', !date ||
        this.element && !this.isDisabled(date));
    }
    var _this = this;

    if(!retry){
      setTimeout(function () {
        console.log("Refreshing view timeout");
        _this.refreshView(true);
        $scope.$apply();
      }, 1);
    }

  };

@haskelcurry
Copy link

@oomkoos, @spirau

I suppose that the cause of the problem here is the one-time binding (ng-repeat="label in ::labels track by $index").
So that the day names get refreshed only when the ng-switch-when condition gets changed, as @spirau mentioned. So, the ugly workaround would be to force this change automatically:

scope.$on('$localeChangeSuccess', function () {
    const mode = scope.datepickerMode;
    scope.datepickerMode = '';
    scope.$$postDigest(() => {
        scope.datepickerMode = mode;
    });
    datepickerCtrl.refreshView();
});

It will flicker when opened, though, but that's not critical for me. The datepicker is always closed when the locale gets changed.

If anyone else figured out a better solution please let us know!
Cheers.

@nlitwin
Copy link

nlitwin commented May 21, 2018

If you're using a later version of Angular UI Bootstrap, replace:
$provide.decorator('datepickerDirective', function($delegate) {
with
$provide.decorator('uibDatepickerDirective', function($delegate) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment