質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.49%

Javascript: 画面遷移について

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,216

score 123

前提・実現したいこと

予約システムのカレンダーを実装しています。
カレンダーをクリックすると、次のalert('JavaScriptのアラート');出力したいです。

発生している問題・エラーメッセージ

setholidayの中が空だと遷移しなくなる

schedule.setHoliday();
エラーメッセージ

該当のソースコード

<input type="hidden" name="off_date" value="<%= booking.booking_date.strftime("%Y-%m-%d-%H:%M") %>",class='off_date' readonly>
    <input type="hidden" name="course" value="<%= booking.booking_course_name.delete!("^0-9") %>",class='course' readonly>
<input type="text" name="id" value="<%= @user.id %>",class='id' readonly>
<input type="text" name="holiday" value="<%= @user.holiday %>",class='holiday' readonly>
  <div id="calendar"></div>
 <input type="text" name="booktime" value="" class= "booktime" id="booktime" readonly>
    {
      const
        day_name = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],
        day_jname = ['(日)', '(月)', '(火)', '(水)', '(木)', '(金)', '(土)'],
        doc = document,
        DEF_OPTION = { };

      const
        A = (e, ...a) => a.map (a => e.appendChild (doc.createElement (a))),
        B = (d, n) => d.setDate (d.getDate () + n),
        C = d => [d.getFullYear (), '年', d.getMonth () + 1 , '月'].join (''),
        D = d => [('0' + d.getHours ()).slice (-2), ('0' + d.getMinutes ()).slice (-2)].join (':'),
        E = (e, d) => {
          let
            [a,,b] = A (e, 'label', 'br', 'label'),
            w = d.getDay () ;
          a.textContent = d.getDate ();
          b.textContent = day_jname[w];
          e.classList.add (day_name[w]);
        },
        F = d => {
          let m = d.getMonth ();
          return [0,31,59,90,120,151,181,212,243,273,304,334][m] + d.getDate() - 1 +
          (new Date (d.getFullYear (), m + 1,0) === 29 && 0 < m);
        },
        H = d => new Date (d.getFullYear (), d.getMonth (), d.getDate ()),
        I = d => [('0' + d.getUTCHours ()).slice (-2), ('0' + d.getUTCMinutes ()).slice (-2)].join (':');

      //_____________


      class Schedule {

        constructor (date = new Date, range = 7, plan = [ ], option = DEF_OPTION) {
          this.current = H (date);//表の左端の日付、これを基準とする
          this.date    = H (date);
          this.range   = range;  //何日分を表示するか
          this.plan    = plan; //予定表が構成される
          this.table   = document.createElement ('table');
          this.option  = Object.assign ({ }, option);

          this.remake ();
        }


        add (day = this.range) {
          let d = H (this.current);
          d.setDate (d.getDate () + day);
          if (+this.date <= +d)
            this.current = d;
          return this;
        }


        setHoliday (...dayNo) {
          let
            year   = this.current.getFullYear (),
            start  = new Date (year, 0, 1),
            end    = new Date (year, 12, 1),

            b = new Date (Date.UTC (1970,0,1, 0, 0)),
            e = new Date (Date.UTC (1970,0,1,24, 30)),
            s = new Date (Date.UTC (1970,0,1, 0,30));

          dayNo.forEach (n => {
            let current = new Date (start);

            current.setDate (7 - current.getDate () + n);

            for (; current < end; current.setDate (current.getDate () + 7)) {
              let idx = F (current);

              for (let c = b; c < e; c = new Date (+s + (+c))) {
                let key = I (c);
                if (! this.plan[key])
                  this.plan[key] = [ ];
                this.plan[key][idx] = true;
              }
            }
          });

          return this;
        }

        //Booking
        setBook (date, occupancyTime) {
          let
            current = new Date (date),
            dayNo = F (current),
            sTime = 30,
            step = new Date (Date.UTC (1970,0,1, 0, sTime)),
            cnt = Math.floor (occupancyTime / sTime);

          for (let i = 0; i < cnt; i++) {
            let time = D (current);
            if (! this.plan[time])
              this.plan[time] = [ ];
            this.plan[time][dayNo] = true;
            current.setTime (+current +(+step));
          }
          return this;
        }

    remake () {
      let t = this.table;
      t.innerText = '';

      let
        h = t.createTHead (),
        tr0 = h.insertRow (-1),
        tr1 = h.insertRow (-1),
        d = H (this.current),
        s = tr0.insertCell (-1),
        c = 1,
        m = d.getMonth ();

      for (let i = 0; i < this.range; i++, c++, B (d, 1)) {
        let td = tr1.insertCell (-1);
        if (m !== d.getMonth ()) {
          s.colSpan = c - 1;
          s = tr0.insertCell (-1);
          m = d.getMonth ();
          c = 1;
        }
        s.textContent = C (d);
        E (td, d);
      }
      s.colSpan = c - 1;

      let e = tr0.insertCell (0);
      e.textContent = '前の一週間';
      e.classList.add ('button');
      e.rowSpan = 2;
      this.prev_btn = e;

      e = tr0.insertCell (-1);
      e.textContent = '次の一週間';
      e.classList.add ('button');
      e.rowSpan = 2;
      this.next_btn = e;

      //__
      let
        begin = new Date (Date.UTC (1970,0,1, 9, 0)),
        end   = new Date (Date.UTC (1970,0,1,21, 30)),
        step  = new Date (Date.UTC (1970,0,1, 0,30)),
        o = F (this.current),
        [tb] = A (t, 'tbody');

      for (let d = begin; d < end; d = new Date (+step + (+d))) {
        let
          b = I (d),
          c = this.plan[b] || [],
          tr = tb.insertRow (-1);

        tr.insertCell (-1).textContent = b;
        for (let i = 0; i < this.range; i++) {
          let td = tr.insertCell (-1);
          if (c[o + i]) {
            td.textContent = '-';
            td.classList.add ('invalid');

          }
          else {
            td.textContent = '◎';
            td.classList.add ('valid');
            td.style.color = '#fd5c63';
            td.style.backgroundColor = 'white';
          }
        }
        tr.insertCell (-1).textContent = b;
      }

      return this;
    }


        handleEvent (event) {
          let t = event.target;
          if (t === this.prev_btn) this.add (-this.range).remake ();
          if (t === this.next_btn) this.add ( this.range).remake ();

          let cbfunc = this.option.handleEvent;
          if ('function' === typeof cbfunc)
            cbfunc.call (this, event);
        }


        static convert (ary) {
          let rst = { };
          ary.forEach (a => {
            let
              dt = new Date (a + ':00.000+09:00'),
              tm = D (dt),
              dn = F (dt);
            if (! rst[tm])
              rst[tm] = [];
            rst[tm][dn] = true;
          });
          return rst;
        }
        //追記
        static getDayPlan (obj, dt) {
          let idx = [ ];
          let dn = F (dt);
          for (let i = 0; i < 24; i+= 1) {
            let h = ('0' + i).slice (-2);
            idx.push (h + ':00');
            idx.push (h + ':30');
          }
          return idx.map (i => [i, !!obj.plan[i][dn]]);
        }
      }

      this.Schedule = Schedule;
    }

    //_____________
    function strDateJp (date) {
      let [y, m, d] = ['getFullYear', 'getMonth', 'getDate'].map (fc => date[fc]());
      return `${y}${m+1}${d}日`;
    }

    //___________________________
    function daysCount(key){

      if (window.matchMedia( "(min-width: 400px)" ).matches) {
        /* ビューポートの幅が 400 ピクセル以上の場合のコードをここに */
          return 14;
        } else {
        /* ビューポートの幅は 400 ピクセル未満の場合のコードをここに */
          return 7;
        }
    }

    const
      BUSY = ['2019-02-19T14:30', '2019-02-21T14:30'],
      plan = Schedule.convert (BUSY),
      schedule = new Schedule (new Date, daysCount(), plan),
      table = schedule.table;

    table.border = 1;

    // 昼休みがあるのが日火木土
    schedule.setHoliday();

    //予約入った時 例) 2月24日 9時30 2時間コースと予約が入った時
    schedule.setBook (new Date (2019, 2, 24, 9, 30), 120).remake ();

    document
      .querySelector ('#calendar')
      .appendChild (table)
      .addEventListener ('click', schedule, false);

    table.addEventListener('click', event => {
      const target = event.target;

      if (target.nodeName !== 'TD')
        return;

      if ('◎' !== target.textContent)
        return;

      let booktime = parseInt (document.querySelector ('#booktime').value, 10);

      let cur = schedule.current;

      let x = target.cellIndex;

      let y = target.parentNode.rowIndex - 2;

      let tgt = new Date (cur);
      tgt.setDate (tgt.getDate () + x -1);

      let plan = Schedule.getDayPlan (schedule, tgt);
      console.log(plan);

      plan = plan.slice (18, 31);

      let rng = booktime / 30 |0;
      plan = plan.slice (y, y + rng);

      if (rng === plan.length && plan.every (a=> !a[1])){
        var id = Array.from(document.getElementsByName('id'), x => x.value);

        if (!(target.closest('tbody') && 1 <= target.cellIndex && target.cellIndex <= 14)) {
            return true;
          }
          const
            time = target.parentNode.cells[0].textContent,
            table = target.closest('table'),
            date = table.tHead.rows[1].cells[target.cellIndex - 1].textContent.replace(/[^0-9]/g, ''),
            ymrow = table.tHead.rows[0],
            ym = (target.cellIndex <= ymrow.cells[1].colSpan ? ymrow.cells[1] : ymrow.cells[2]).textContent;

          let
            value = ym + date + '日' + time,
            param = document.getElementById( "booktime" ).value;
            alert('JavaScriptのアラート');
      }else{
          alert("その時間帯は予約は出来ません。");
      }
    }, false);

補足情報(FW/ツールのバージョンなど)

ES6

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • nanase21

    2019/04/08 20:35 編集

    このコメントは気になされないでください。

    キャンセル

  • Lhankor_Mhy

    2019/04/09 15:51

    その行を削除したところ、document.querySelector('#booktime') がない、というエラーが出ました。

    もう少し、質問を整理してみてはいかが?

    キャンセル

  • nanase21

    2019/04/09 18:11

    失礼しました。その行ではコース時間について取得していました。
    #booktimeでは、textfieldの値を取得しています。(例:60分)を取得していてその値とカレンダーを照らし合わせており予約可能かどうかを判定しています。

    キャンセル

回答 1

checkベストアンサー

+1

すみませんが、何が聞きたいのかが理解できませんでした。
提示のソースをonloadで実行すると別のエラー(#booktimeが無い)が出ます。setHolidayではエラーは出ていないように見えます。

ご自分が何をしたいか、何に困っているかは、正確に把握されていますでしょうか?
画面遷移をしたいだけならば、エラーが出る処理を全てそぎ落とせば良いわけです。必要な処理なのにエラーが出てしまっているならば、その部分だけを抜き出して質問したほうがいいです。

直接の解決方法ではないですが、以下を試してみると自己解決できるかもしれません。

  • フローチャートを書き出してみる
  • 変数、関数には正しく名づける
  • HTMLの生成と内部処理を分ける
  • コメントを書く

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る