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;
         });
    });

`

Надеюсь, это кому-нибудь поможет.

Другие вопросы по тегам