Angular - ui-bootstrap - datepicker - Есть ли способ определить, когда месяц изменился?
Я бы хотел установить дату 1-го числа текущего выбранного месяца, когда он изменился.
Есть ли способ без отслеживания события нажатия на кнопки месяца?
Тиа Сэм
4 ответа
К сожалению, datepicker
Директива не имеет привязки для отслеживания изменения месяца / года. Вот то, что я придумал как обходной путь.
В HTML...
<datepicker month-changed="changeMonth($month, $year)" />
В контроллере...
$scope.changeMonth = function(month, year) {
console.log(month, year);
// set your date here if you need to
// in my case, i needed to request some results via ajax
};
Декоратор
app.config(function($provide) {
$provide.decorator('datepickerDirective', function($delegate) {
var directive = $delegate[0],
link = directive.link;
angular.extend(directive.scope, { 'monthChanged': '&' });
directive.compile = function() {
return function(scope, element, attrs, ctrl) {
link.apply(this, arguments);
scope.$watch(function() {
return ctrl[0].activeDate.getTime();
}, function(newVal, oldVal) {
if (scope.datepickerMode == 'day') {
oldVal = moment(oldVal).format('MM-YYYY');
newVal = moment(newVal).format('MM-YYYY');
if (oldVal !== newVal) {
var arr = newVal.split('-');
scope.monthChanged({ '$month': arr[0], '$year': arr[1] });
}
}
});
};
};
return $delegate;
});
});
Еще один декоратор
Вот еще один декоратор, который также работает, но, вероятно, немного более ресурсоемкий. Все, что я здесь делаю, это перезаписываю isActive()
метод уже используется в директиве, поэтому вместо этого вызывается мой метод. Я публикую это только как пример возможных способов обойти некоторые ограничения в сторонних директивах. Я не обязательно рекомендую это решение.
app.config(function($provide) {
$provide.decorator('datepickerDirective', function($delegate) {
var directive = $delegate[0],
link = directive.link;
angular.extend(directive.scope, { 'monthChanged': '&' });
directive.compile = function() {
return function(scope, element, attrs, ctrl) {
link.apply(this, arguments);
var activeMonth, activeYear, activeFn = scope.isActive;
scope.isActive = function(dateObj) {
if (scope.datepickerMode == 'day' && !dateObj.secondary) {
var oldMonth = activeMonth, oldYear = activeYear,
newMonth = dateObj.date.getMonth() + 1;
newYear = dateObj.date.getFullYear();
if (oldMonth !== newMonth || oldYear !== newYear) {
activeMonth = newMonth;
activeYear = newYear;
scope.monthChanged({ '$month': newMonth, '$year': newYear });
}
}
activeFn(dateObj);
};
};
};
return $delegate;
});
});
Область действия Datepicker имеет свойство 'activeDateId', которое вы можете наблюдать. Это меняется, когда вы меняете месяцы.
Я думаю, что лучший способ - создать "декоратор" в директиве datepicker, чтобы вы могли добавить к нему функциональность. Вы можете получить доступ к его области действия, если переопределите функцию 'compile' директивы.
Вы делаете это в функции module.config:
$provide.decorator('datepickerDirective', function($delegate) {
var directive = $delegate[0];
/* Override compile */
var link = directive.link;
directive.compile = function() {
return function(scope, element, attrs, ctrl) {
link.apply(this, arguments);
scope.$watch('activeDateId', function() {
console.log('switched');
});
}
};
return $delegate;
});
РЕДАКТИРОВАТЬ
Я столкнулся с проблемой с кодом, похожим на этот: когда вы меняете месяц, и у двух месяцев будет 1-е число в один и тот же день, $ watch не сработает. Вы можете обойти это, наблюдая за значением свойства 'activeDate' в контроллере Datepicker:
scope.$watch(function() {
return ctrl.activeDate.getTime();
}, function() {
console.log('switched');
});
Поместите $watch на модель, с которой связан сборщик даты:
<datepicker ng-model="data.date" min-date="minDate" show-weeks="true" class="well well-sm"></datepicker>
$scope.$watch('data.date', function(){
//date has changed
});
У меня была такая же проблема, когда я пытался установить модель ng на первый день января, когда они выбирают год. Ответы @Rob и @spongessuck действительно помогли мне. Вот как я это решил. Всякий раз, когда вы выбираете год или месяц, переменная activeDate
устанавливается я использую $setViewValue
установить модель на activeDate
наблюдая за переменной datepickerMode
который меняется всякий раз, когда вы выбираете год, месяц или дату.
`
app.config(function ($provide) {
$provide.decorator('datepickerDirective', function ($delegate) {
var directive = $delegate[0],
link = directive.link;
directive.compile = function () {
return function (scope, element, attrs, ctrl) {
link.apply(this, arguments);
scope.$watch('datepickerMode', function (newValue, oldValue) {
if (newValue!=oldValue && newValue == 'month') {
ctrl[1].$setViewValue(ctrl[0].activeDate);
}
});
};
};
return $delegate;
});
});
`
Надеюсь, это кому-нибудь поможет.