Это часть 2 живого руководства, вы не сможете следовать ему, если не пройдете часть 1. (Часть 3 здесь)

Добро пожаловать назад. Здесь, в Неми, тихое и солнечное воскресенье, нет ничего лучше, чем послушать благоприятную мелодию и продолжить работу над датпикером.

Вот что у нас получилось:

Прежде чем мы пойдем дальше, мне нужно сделать существующий код более рациональным, например:

Переименуйте переменные и функции:

  • viewDate - ›navDate
  • changeViewDate - ›changeNavMonth
  • canChange - ›canChangeNavMonth

changeNaveMonth теперь принимает только один аргумент:

changeNavMonth(num: number){
    if(this.canChangeNavMonth(num)){
    this.navDate.add(num, 'month');
    }
}

canChangeNavMonth также принимает только один аргумент:

canChangeNavMonth(num: number): boolean{
    const clonedDate = moment(this.navDate);
    clonedDate.add(num, 'month');
    const minDate = moment().add(-1, ‘month’);
    const maxDate = moment().add(1, ‘year’);
    return clonedDate.isBetween(minDate, maxDate);
}

Это было необходимо? Нет, но это делает его более читабельным. Теперь давайте отключим кнопку с шевроном, если дата выходит за пределы указанного диапазона. Все, что нам нужно сделать, это добавить такую ​​директиву к нашим кнопкам:

[disabled] = “!canChangeNavMonth(-1)” 

В заключение, это новые datepicker.component.ts и datepicker.component.html:

Намного лучше. И вот чего мы добились:

А теперь пора сделать и этот небольшой заголовок буднего дня динамичным.

5 - Маленький заголовок буднего дня

Оказывается, у каждого региона свой официальный первый день недели. В Великобритании воскресенье. В Италии, где я сейчас нахожусь, понедельник. Последовательность представлена ​​числами от 0 до 6 как в датах JS, так и в объектах Moment.js. В Moment.js на будний день можно ссылаться по его номеру в соответствии с языковыми стандартами с помощью метода weekday (). Итак, британское воскресенье или итальянский понедельник (в зависимости от региона) будет:

moment().weekday(0);

Чтобы отобразить его в удобочитаемом формате, всего с тремя буквами, как нам нужно:

moment().weekday(0).format(‘ddd’);

Будет отображено «Sun» (локаль «en») или «lun» (локаль «it»; да, в этой локали оно не пишется с заглавной буквы). Чтобы отобразить заголовок, все, что нам нужно сделать, - это перебрать эту строку кода по массиву чисел от 0 до 6. На самом деле. Итак, в нашем компоненте мы можем объявить пустой массив строк, представляющих наш заголовок (weekDaysHeaderArr), и заполнить его в ngOnInit с помощью простой функции makeHeader:

И, наконец, замените жестко запрограммированный заголовок на ngFor в нашем datepicker.component.html:

Мы сделали это! Вот локаль "it":

К сожалению, похоже, что в Angular нет встроенного конвейера с заглавными буквами. Мы подумаем об этом позже. Хорошая работа!

6 - Фактические… даты!

Мы могли бы делать в нашем шаблоне всевозможные запутанные ngFor - ngIf - ngSwitch, чтобы правильно отображать эти маленькие числа. Но я предпочитаю ограничить логику в файле ts и передать шаблону простой массив для итерации.

Наша цель - создать массив, содержащий нули для любого пустого пространства сетки и номер дня для любого дня месяца. Кроме того, я также хочу знать, доступна ли дата для выбора. Имеет смысл? Допустим, в отображаемом месяце 30 дней, он начинается во вторник, и мы используем локаль «en», массив должен быть примерно таким:

[{value: 0, available: false}, {value: 0, available: false}, {value: 1, available: true}, {value: 2, available: true},..., {value: 30, available: true}, {value: 0, available: false}, {value: 0, available: false}]

Для любого данного месяца длина этого массива будет равна: количеству дней в месяце + количеству дней между первым днем ​​недели в соответствии с локалью, в которой мы находимся, и первым днем ​​месяца + количество дней между последним днем ​​месяца и последним днем ​​недели в локали.

Холодно, мы используем Moment.js. Чтобы получить дату, представляющую первый день месяца, который мы отображаем (не забывайте всегда клонировать дату, прежде чем изменять ее, если вы не собираетесь ее менять):

const firstDayDate = moment(navDate);
firstDayDate.startOf('month');

Чтобы узнать номер дня недели и, следовательно, сколько пустых ячеек нам нужно распечатать перед выводом чисел:

const initialEmptyCells = firstDayDate.weekday();

Точно так же мы можем подсчитать, сколько пустых ячеек содержит массив в конце (на этот раз проверяя, сколько ячеек нам нужно пройти оттуда до конца недели):

const lastDayDate = moment(navDate);
lastDayDate.endOf('month');
const lastEmptyCells = 6 - lastDayDate.weekday();

Чтобы узнать общее количество отображаемых дней в месяце:

const daysInMonth = navDate.daysInMonth();

Итак, массив, который мы хотим построить, имеет следующую длину:

const arrayLength = initialEmptyCells + lastEmptyCells + daysInMonth;

Теперь, когда мы знаем его длину, мы можем приступить к его созданию с помощью цикла for:

let gridArr: Array<number> = [];
for(let i = 0; i< arrayLength; i++){
    let obj = {};
    if(i<initialEmptyCells || i>initialEmptyCells + daysInMonth -1){
        obj.value = 0;
        obj.available = false;
    } else {
        obj.value = i - initialEmptyCells +1;
        obj.available = isAvailable(i - initialEmptyCells +1);
    }
    gridArr.push(obj);
}

Где isAvailable - это функция, которая будет принимать число и проверять, доступен этот день или нет. На данный момент он будет просто возвращать true все время, кроме числа 5, просто чтобы посмотреть, как выглядит отключенная кнопка:

isAvailable(num: number){
    if(num === 5){return false};
    else {return true};
}

Блин, теперь мне нужно написать код ... подождите ...

Итак, мы объявляем переменную gridArr, которая будет содержать наш массив, и функцию makeGrid, которая создаст его в зависимости от отображаемой текущей даты:

Мы будем вызывать функцию ngOnInit и каждый раз обновлять navDate.

Теперь мы можем, наконец, избавиться от жестко запрограммированной сетки в нашем шаблоне, пройдя цикл по gridArr и добавив класс «is-disabled», если день недоступен:

И вот результат (помните, мы отключили каждую пятую просто ради этого):

Молодец!! Теперь нам просто нужно захватить дату, когда мы ее выберем. Но для этого нам понадобится… часть 3 !!