【フォームブリッジ】カレンダーで当日以前を選択できないようにしたい

背景・実現したいこと

表題の通りです。

どのようにすれば良いのか全く検討がつかない状態です。

利用したソースコード

(function () {
  fb.events.fields.da.mounted = [
      function(state) {
        document.addEventListener('click', function(e){
          var element=e.target, row, cell;
          while(element.parentNode.classList){
            if(element.classList.contains('el-date-table__row')) row = element;
            if(element.parentNode.classList.contains('el-date-table__row')) cell = element;
            element = element.parentNode;
          }
          if(row && cell){
            if([].slice.call(row.children).indexOf(cell)===0 || [].slice.call(row.children).indexOf(cell)===6){
              e.stopPropagation();
              alert('土日は選択できません');
            }
          }
        }, true);

      }
  ]

})();

現在は上記の通りにして土日を選択できないようにしています。

ここに追加する形で当日以前の日付を選択できないようにしたいです。

こちらと

https://developer.cybozu.io/hc/ja/community/posts/360025921251–%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%83%96%E3%83%AA%E3%83%83%E3%82%B8-%E6%97%A5%E4%BB%98%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

 

こちらを

https://developer.cybozu.io/hc/ja/community/posts/360016773086-%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%83%96%E3%83%AA%E3%83%83%E3%82%B8-%E3%81%A7%E6%9C%AC%E6%97%A5%E3%81%8B%E3%82%89%EF%BC%91%E3%83%B6%E6%9C%88%E4%BB%A5%E4%B8%8A%E5%BE%8C%E3%81%AE%E6%97%A5%E4%BB%98%E3%81%97%E3%81%8B%E9%81%B8%E6%8A%9E%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B

を参照しました。

上記の土日制御とは別にバリデーションを記述した方がよろしいでしょうか?

ikkaさん

こんにちは。

 

記載のコードに追記する形ですと以下一例です。

カレンダーのヘッダー要素から年・月を取得し、クリックした日付セルと結合してYYYYMMDD文字列を作ります。

これと現在日付をYYYYMMDD変換した文字列を比較します。

 

当月カレンダー内の前月日付・翌月日付(薄い日付文字)は選択できないようにしています(アラートを出す)。

日付判定できないわけではないですが、処理が複雑になるためです。

if (row && cell) {
    if ([].slice.call(row.children).indexOf(cell) === 0 || [].slice.call(row.children).indexOf(cell) === 6) {
        e.stopPropagation();
        alert('土日は選択できません');
        return state;
    }

    // カレンダーのヘッダー要素(YYYY年M月)
    const elHeader = cell.closest('.el-picker-panel__body').querySelector('.el-date-picker__header');

    // 選択した日付をYYYYMMDD文字列で格納
    const year = elHeader.querySelectorAll('.el-date-picker__header-label')[0].textContent.replace(/[^0-9]/g, '');
    const month = ('00' + elHeader.querySelectorAll('.el-date-picker__header-label')[1].textContent.replace(/[^0-9]/g, '')).slice(-2);
    const day = ('00' + cell.textContent.replace(/[^0-9]/g, '')).slice(-2);
    const strDate = year + month + day;

    // 現在日付をYYYYMMDD文字列で格納
    const now = new Date();
    const strNow = now.getFullYear() + ('00' + (now.getMonth() + 1)).slice(-2) + ('00' + now.getDate()).slice(-2);

    // 選択した日付が翌月部分の場合は切り替えを促す
    if (cell.closest('.next-month')) {
        e.stopPropagation();
        alert('翌月の日付を選択する場合はカレンダーを翌月に切り替えてください。');
        return state;
    }

    // 選択した日付が当日以前の場合は選択不可
    if (cell.closest('.prev-month') || strDate <= strNow) {
        e.stopPropagation();
        alert('当日以前は選択できません');
        return state;
    }
}

koichiさん

いつもありがとうございます!

教えていただいたコードですんなりできました!!

ありがとうございました!

 

大変恐縮なのですが、2点ほど追加で質問させていただければ幸いです。

1)当日も選択可能にするにはどうしたらいいでしょうか?

2)当日選択可能にした上で、可能であれば時間選択の制限ができればと思っています。

カレンダーの下にドロップダウンで時間選択フィールドを作成しています。

時刻フィールドを使用せずに「10時開始(11時終了)」「11時開始(12時終了)」…という形で設定しています。

こちらの時間選択を当日の場合2時間後以降の選択肢でないと選択できないようにしたいと思っています。

例えば、当時の13時に選択する場合「15時開始(16時終了)」以降しか選択できないようにするというものです。

時刻フィールドではなくただのドロップダウンなので難しいとは思いますが、もしも方法をご存知でしたらと思い質問させていただきました。

お手数お掛けいたしますが何とぞよろしくお願いいたします。

  1. 当日も選択可能ということはif条件を変えれば良いです。

当日不可

if (cell.closest('.prev-month') || strDate <= strNow) {

当日可

if (cell.closest('.prev-month') || strDate < strNow) {

 

  1. 時刻もドロップダウンから時刻部分を抽出できれば可能です。

丸々答えになってしまいますが、ドロップダウン選択値の頭の数値を取得。

その数値の2時間前の時刻をHH文字列として保持。

const strHour = ('00' + (Number(hour.textContent.split('時')[0]) - 2)).slice(-2);

これと現在時刻のHH文字列を大小比較し、条件に合致すればアラート。

(function() {
    fb.events.form.mounted = [function(state) {
        document.addEventListener('click', function(e) {
            var element = e.target, row, cell, hour;
            while (element.parentNode.classList) {
                if (element.classList.contains('el-date-table__row')) row = element;
                if (element.parentNode.classList.contains('el-date-table__row')) cell = element;
                if (element.classList.contains('el-select-dropdown__item')) hour = element;
                element = element.parentNode;
            }

            // 現在日付をYYYYMMDD文字列で格納
            const now = new Date();
            const strNow = now.getFullYear() + ('00' + (now.getMonth() + 1)).slice(-2) + ('00' + now.getDate()).slice(-2);
            const strNowHour = ('00' + now.getHours()).slice(-2);

            if (row && cell) {
                if ([].slice.call(row.children).indexOf(cell) === 0 || [].slice.call(row.children).indexOf(cell) === 6) {
                    e.stopPropagation();
                    alert('土日は選択できません');
                    return state;
                }

                // カレンダーのヘッダー要素(YYYY年M月)
                const elHeader = cell.closest('.el-picker-panel__body').querySelector('.el-date-picker__header');

                // 選択した日付をYYYYMMDD文字列で格納
                const year = elHeader.querySelectorAll('.el-date-picker__header-label')[0].textContent.replace(/[^0-9]/g, '');
                const month = ('00' + elHeader.querySelectorAll('.el-date-picker__header-label')[1].textContent.replace(/[^0-9]/g, '')).slice(-2);
                const day = ('00' + cell.textContent.replace(/[^0-9]/g, '')).slice(-2);
                const strDate = year + month + day;

                // 選択した日付が翌月部分の場合は切り替えを促す
                if (cell.closest('.next-month')) {
                    e.stopPropagation();
                    alert('翌月の日付を選択する場合はカレンダーを翌月に切り替えてください。');
                    return state;
                }

                // 選択した日付が当日以前の場合は選択不可
                if (cell.closest('.prev-month') || strDate < strNow) {
                    e.stopPropagation();
                    alert('当日以前は選択できません');
                    return state;
                }
            }

            if (hour) {
                // 選択した2時間前のHH文字列
                const strHour = ('00' + (Number(hour.textContent.split('時')[0]) - 2)).slice(-2);
                if (strNowHour > strHour) {
                    e.stopPropagation();
                    alert('2時間後以降を選択してください');
                    return state;
                }
            }

        }, true);
    }];
})();

koichiさん

ありがとうございます!!

当日選択可能、2時間後以降も可能になりました!

ただ、当日以外の日にも2時間後以降の制限がかかるようになっております。

何度も本当に申し訳ありませんが、2時間後以降の制限を当日のみに反映させるにはどのようにしたらよろしいでしょうか?

お教えいただければ幸いです。

何とぞよろしくお願いいたします。

当日のみでしたね。完全に抜けてました。

選択した日付と本日が一致しているかどうかで判定すれば良いです。

日付フィールドの値をYYYYMMDDに変換し、先に定義したstrNow(本日)と比較します。

// 選択した日付をYYYYMMDD文字列で格納
const date = new Date(record.日付フィールド.value);
const strDate = date.getFullYear() + ('00' + (date.getMonth() + 1)).slice(-2) + ('00' + date.getDate()).slice(-2);

if (strDate == strNow && hour) {
// 選択した2時間前のHH文字列
const strHour = ('00' + (Number(hour.textContent.split('時')[0]) - 2)).slice(-2);
if (strNowHour > strHour) {
  e.stopPropagation();
  alert('2時間後以降を選択してください');
  return state;
}
}

koichiさん

ありがとうございます!!

初歩的な質問で恐縮なのですが、

// 選択した日付をYYYYMMDD文字列で格納
const date =newDate(record.日付フィールド.value);
const strDate = date.getFullYear() + ('00'+ (date.getMonth() +1)).slice(-2) + ('00'+ date.getDate()).slice(-2);

の位置は

if (strDate == strNow && hour) {
// 選択した2時間前のHH文字列
conststrHour = ('00'+ (Number(hour.textContent.split('時')[0]) -2)).slice(-2);
if(strNowHour > strHour) {
  e.stopPropagation();
  alert('2時間後以降を選択してください');
 returnstate;
}
}

の上でよろしいでしょうか?

こちらの上に置いたところ、当日の2時間後制限が効かなくなってしまいました。

// 選択した日付をYYYYMMDD文字列で格納
               constyear = elHeader.querySelectorAll('.el-date-picker\_\_header-label')[0].textContent.replace(/[^0-9]/g,'');
               constmonth = ('00'+ elHeader.querySelectorAll('.el-date-picker\_\_header-label')[1].textContent.replace(/[^0-9]/g,'')).slice(-2);
               constday = ('00'+ cell.textContent.replace(/[^0-9]/g,'')).slice(-2);
               conststrDate = year + month + day;

の上下に置いてみたり色々と試してみたのですが、当日以前や土日の制限が効かなくなったりしてしまいました。

またお手数おかけしてしまいますがお教えいただければ幸いです。

何とぞよろしくお願い申し上げます。

2回目に上げたコードの最後の方の以下部分を丸々変えたらいけるはずです。

if (hour) {
    // 選択した2時間前のHH文字列
    const strHour = ('00' + (Number(hour.textContent.split('時')[0]) - 2)).slice(-2);
    if (strNowHour > strHour) {
        e.stopPropagation();
        alert('2時間後以降を選択してください');
        return state;
    }
}

 

上記を以下に変える

// 選択した日付をYYYYMMDD文字列で格納
const date = new Date(record.日付フィールド.value);
const strDate = date.getFullYear() + ('00' + (date.getMonth() + 1)).slice(-2) + ('00' + date.getDate()).slice(-2);

if (strDate == strNow && hour) {
    // 選択した2時間前のHH文字列
    const strHour = ('00' + (Number(hour.textContent.split('時')[0]) - 2)).slice(-2);
    if (strNowHour > strHour) {
        e.stopPropagation();
        alert('2時間後以降を選択してください');
        return state;
    }
}

 

Koichiさん

重ね重ねありがとうございます!!

丸々変えてみたのですが、やはり当日予約の制御ができない状態でした。

何度も質問してしまい大変お手数おかけいたしました。

今回は当日以前の予約ができない状態にするのが必須で、当日予約の制御はマストではないようですので、こちらで完成ということにしたいと思います。

この度も本当にお世話になりました。

ありがとうございました!

ご確認ありがとうございます。

もしかしたらフォームの作り方の違いによるのかもしれません。

 

すみません。

最後に一つだけ、以下コードの「日付フィールド」の部分が、該当の日付フィールドのフィールドコードになっているかだけ、ご確認ください。

※念のため、recordの前に「state.」も付けました。

const date = new Date(state.record.日付フィールド.value);

Koichiさん

こちらこそご確認いただきありがとうございます!!

大変申し訳ございませんでした。

日付フィールドが該当の日付フィールドになっておりませんでした…。

本当に何もわかっておらずお手数をおかけしてしまいすみませんでした。

お教えいただいた方法で、当日以前の予約不可も当日2時間後制限もバッチリできました!

長々とした質問になってしまったのにも関わらず、ご対応いただきありがとうございました!

フィールドコードでしたね。

解決して良かったです!

本当にすみませんでした…。

今回も丁寧にご対応いただき、誠にありがとうございました!!!