-
-
Save cgmartin/3daa01f910601ced9cd3 to your computer and use it in GitHub Desktop.
/** | |
* 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; | |
}); | |
}); |
Hey brian, this doesn't seem to work for me. I've even gone so far as to include it inline in ui-bootstrap.js and it throws a dependency error:
Uncaught Error: [$injector:modulerr] Failed to instantiate module MyApp due to:
Error: [$injector:modulerr] Failed to instantiate module ui.bootstrap due to:
Error: [$injector:modulerr] Failed to instantiate module ui.bootstrap.datepicker due to:
Error: [$injector:unpr] Unknown provider: a
Great, it works!
Wow that is exactly what I was looking for.
I am using the custom-class option in combination with a function that parses $resource
data that is available after the initial rendering of the datepicker.
However there seems to be a problem with the pure rendering in my use-case. For the invalidation I can confirm this works. When attaching custom classes however the corresponding function $scope.getDayClass
gets called (broadcasting fires correctly) but nothing changes on the datepicker itself. After navigating a month forth and back everything renders as expected.
Anyone got an idea what might help?
EDIT
The following hack does show the classes correctly..but of course causes the datepicker to flicker forth and back
scope.$on('refreshDatepickers', function refreshView() {
console.log("refreshing picker");
datepickerCtrl.activeDate.setMonth(datepickerCtrl.activeDate.getMonth()+1);
datepickerCtrl.refreshView();
$timeout(function () {
datepickerCtrl.activeDate.setMonth(datepickerCtrl.activeDate.getMonth()-1);
datepickerCtrl.refreshView();
}, 1);
});
I couldn't find another combination that works without flickering.
Using version 0.14.2, you need to change "datepickerDirective" to "uibDatepickerDirective".
I wanted to update the datepicker on locale change using dynamic-locale. So I directly connected the datepicker refresh to the $localeChnageSuccess event. That's working but only for the month name. The labels for the days are well defined in the new language in the datePicker array due to the forced refreshView, but not refreshed by angular itself.
Even when playing manually with the datepicker the day names dont't change. The new day names only appear if I go to a month view then back to the day view. Where is the binding!
Any idea how to fix it?
.config(function ($provide) {
$provide.decorator('uibDatepickerDirective', function($delegate) {
angular.forEach($delegate, function (directive) {
var originalCompile = directive.compile;
var originalLink = directive.link;
if (originalCompile) {
directive.compile = function () {
return function (scope, element, attrs, ctrls) {
originalLink.apply(this, arguments);
var datepickerCtrl = ctrls[0];
var ngModelCtrl = ctrls[1];
if (ngModelCtrl) {
scope.$on('$localeChangeSuccess', function () {
datepickerCtrl.refreshView();
});
}
};
}
}
});
return $delegate;
});
})
...
I want to stop scrolling calendra to go next month and next year. In short, I want to disable arrows(move) and toggling in calendar header. I tried to decorate using below code
angular.module('ui.bootstrap.datepicker') .config(function($provide) { $provide.decorator('uibDatepickerDirective', function($delegate)
but getting error like Uncaught Error: [$injector:modulerr] Failed to instantiate module myApp due to: Error: [$injector:modulerr] Failed to instantiate module ui.bootstrap due to: Error: [$injector:modulerr] Failed to instantiate module ui.bootstrap.datepicker due to: Error: [$injector:unpr] Unknown provider: uibDatepickerDirectiveProvider
it looks like injection error.
This was very helpful and worked perfectly for me! Thank you very much.
@extropianer
Did you ever find a none-flicker-solution to this issue? :)
@spirau or anyone else using uib-datepicker and dynamic-locale ....
did you manage to get the uib-datepicker day names to also refresh?
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);
}
};
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.
If you're using a later version of Angular UI Bootstrap, replace:
$provide.decorator('datepickerDirective', function($delegate) {
with
$provide.decorator('uibDatepickerDirective', function($delegate) {
Hi algil, not sure if this is still a question for you. To use this is easy.
For example, in my controller I'm using it in a $watch:
$scope.$watch('newLeaveRequest.startDate', function (newVal, oldVal) {
if (newVal) {
$scope.endDateMinDate = newVal;
$scope.$broadcast('refreshDatepickers');
}
});