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

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

ただいまの
回答率

90.01%

Js: カレンダーの日にちをたっぷしたらhtmlのinputに反映させたい。

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 913

rails_ruby

score 77

前提・実現したいこと

jsでカレンダーを実装しています。
カレンダー内をtdをくりっくしたらそのクリックした箇所の日付を別途に用意しているinputに反映させたい。

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

jsでカレンダーを表示させるところまでは出来たがその先の日にちをタップした時の日付を習得できずに困っています。

エラーメッセージ

該当のソースコード

<div class="main users-new">
  <div class="container">
      <input type="text" value="today" onselect="click_date" readonly>
      <div id="calendar"></div>
  </div>
</div>
window.onload = function() {
    // 現在の年月の取得
    var current = new Date();
    var year = current.getFullYear();
    var month = current.getMonth() + 1;

    // カレンダーの表示
    var wrapper = document.getElementById('calendar');
    add_calendar(wrapper, year, month);
}

/**
 * 指定した年月のカレンダーを表示する
 * @param {object} wrapper - カレンダーを追加する親要素
 * @param {number} year    - 年の指定
 * @param {number} month   - 月の指定
 */
function add_calendar(wrapper, year, month) {
    // 現在カレンダーが追加されている場合は一旦削除する
    wrapper.textContent = null;

    // カレンダーに表示する内容を取得
    var headData = generate_calendar_header(wrapper, year, month);
    var bodyData = generate_month_calendar(year, month);

    // カレンダーの要素を追加
    wrapper.appendChild(headData);
    wrapper.appendChild(bodyData);
}

/**
 * 指定した年月のカレンダーのヘッダー要素を生成して返す
 * @param {object} wrapper - カレンダーを追加する親要素
 * @param {number} year    - 年の指定
 * @param {number} month   - 月の指定
 */
function generate_calendar_header(wrapper, year, month) {
    // 前月と翌月を取得
    var nextMonth = new Date(year, (month - 1));
    nextMonth.setMonth(nextMonth.getMonth() + 1);
    var prevMonth = new Date(year, (month - 1));
    prevMonth.setMonth(prevMonth.getMonth() - 1);

    // ヘッダー要素
    var cHeader = document.createElement('div');
    cHeader.className = 'calendar-header';

    // 見出しの追加
    var cTitle = document.createElement('div');
    cTitle.className = 'calendar-header__title';
    var cTitleText = document.createTextNode(year + '年' + month + '月');
    cTitle.appendChild(cTitleText);
    cHeader.appendChild(cTitle);

    // 前月ボタンの追加
    var cPrev = document.createElement('button');
    cPrev.className = 'calendar-header__prev';
    var cPrevText = document.createTextNode('prev');
    cPrev.appendChild(cPrevText);
    // 前月ボタンをクリックした時のイベント設定
    cPrev.addEventListener('click', function() {
        add_calendar(wrapper, prevMonth.getFullYear(), (prevMonth.getMonth() + 1));
    }, false);
    cHeader.appendChild(cPrev);

    // 翌月ボタンの追加
    var cNext = document.createElement('button');
    cNext.className = 'calendar-header__next';
    var cNextText = document.createTextNode('next');
    cNext.appendChild(cNextText);
    // 翌月ボタンをクリックした時のイベント設定
    cNext.addEventListener('click', function() {
        add_calendar(wrapper, nextMonth.getFullYear(), (nextMonth.getMonth() + 1));
    }, false);
    cHeader.appendChild(cNext);

    return cHeader;
}

/**
 * 指定した年月のカレンダー要素を生成して返す
 * @param {number} year  - 年の指定
 * @param {number} month - 月の指定
 */
function generate_month_calendar(year, month) {
    var weekdayData = ['日', '月', '火', '水', '木', '金', '土'];
    // カレンダーの情報を取得
    var calendarData = get_month_calendar(year, month);

    var i = calendarData[0]['weekday']; // 初日の曜日を取得
    // カレンダー上の初日より前を埋める
    while(i > 0) {
        i--;
        calendarData.unshift({
            day: '',
            weekday: i
        });
    }
    var i = calendarData[calendarData.length - 1]['weekday']; // 末日の曜日を取得
    // カレンダー上の末日より後を埋める
    while(i < 6) {
        i++;
        calendarData.push({
            day: '',
            weekday: i
        });
    }

    // カレンダーの要素を生成
    var cTable = document.createElement('table');
    cTable.className = 'calendar-table';

    var insertData = '';
    // 曜日部分の生成
    insertData += '<thead>';
    insertData += '<tr>';
    for (var i = 0; i < weekdayData.length; i++) {
        insertData += '<th>';
        insertData += weekdayData[i];
        insertData += '</th>';
    }
    insertData += '</tr>';
    insertData += '</thead>';

    // 日付部分の生成
    insertData += '<tbody>';
    for (var i = 0; i < calendarData.length; i++) {
        if(calendarData[i]['weekday'] <= 0) {
            insertData += '<tr>';
        }
        insertData += '<td>';
        insertData += calendarData[i]['day'];
        insertData += '</td>';
        if(calendarData[i]['weekday'] >= 6) {
            insertData += '</tr>';
        }
    }
    insertData += '</tbody>';

    cTable.innerHTML = insertData;
    return cTable;
}

/**
 * 指定した年月のカレンダー情報を返す
 * @param {number} year  - 年の指定
 * @param {number} month - 月の指定
 */
function get_month_calendar(year, month) {
    var firstDate = new Date(year, (month - 1), 1); // 指定した年月の初日の情報
    var lastDay = new Date(year, (firstDate.getMonth() + 1), 0).getDate(); // 指定した年月の末日
    var weekday = firstDate.getDay(); // 指定した年月の初日の曜日

    var calendarData = []; // カレンダーの情報を格納
    var weekdayCount = weekday; // 曜日のカウント用
    for (var i = 0; i < lastDay; i++) {
        calendarData[i] = {
            day: i + 1,
            weekday: weekdayCount
        }
        // 曜日のカウントが6(土曜日)まできたら0(日曜日)に戻す
        if(weekdayCount >= 6) {
            weekdayCount = 0;
        } else {
            weekdayCount++;
        }
    }
    return calendarData;
}

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

Javascript 
HTML5
CSS

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • rails_ruby

    2019/01/17 14:49

    mts10806様、papinianus様
    てっきりカーソルのマークは変えられないものだと勘違いしていました。
    そのため、おっしゃっていた大ことを調べてみたところ、cursor:default;でカーソルマークを変更することが出来ました。
    また、開発者ツールでもクリック時に日にちを取得することが出来ましたのでお二人方から教えていただいたことを基にinputに反映できるようにしてみます。
    ありがとうございました。
    お二人方にベストアンサーをお付けしたいですが、今回はpapinianusさんの回答をベストアンサーにさせて頂きたいと思います。

    キャンセル

  • m.ts10806

    2019/01/17 14:51

    cursorは指定次第では利用者のPCよ設定によって開発側の意図通りにならないこともあるのでご注意ください。

    キャンセル

  • papinianus

    2019/01/17 15:04

    inputに反映するコードにしたんで。したんで…たんで…で…

    キャンセル

回答 2

+3

簡単にしたいならtdにonclickで日付渡して

insertData += '<td onclick="setDate(\''+year+'-'+month+'-'+calendarData[i]['day']+'\')">';

その関数で受け取る

function setDate(selectdate){
    console.log(selectdate);
}


あとはそのinputに入れるだけですね。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/01/17 14:15

    tdのクリックってブラウザ大丈夫だっけ・・・(Chromeでは動いた)

    キャンセル

checkベストアンサー

+2

window.onload = function() {
    // 現在の年月の取得
    var current = new Date();
    var year = current.getFullYear();
    var month = current.getMonth() + 1;

    // カレンダーの表示
    var wrapper = document.getElementById('calendar');
    add_calendar(wrapper, year, month);
}

function handler(e) {
    if(e.target.innerText === "") return;
    const yearmonth = document.querySelector(".calendar-header__title").innerText;
    document.querySelector("input").value = yearmonth + e.target.innerText + "日";
}
/**
 * 指定した年月のカレンダーを表示する
 * @param {object} wrapper - カレンダーを追加する親要素
 * @param {number} year    - 年の指定
 * @param {number} month   - 月の指定
 */
function add_calendar(wrapper, year, month) {
    // 現在カレンダーが追加されている場合は一旦削除する
    wrapper.textContent = null;

    // カレンダーに表示する内容を取得
    var headData = generate_calendar_header(wrapper, year, month);
    var bodyData = generate_month_calendar(year, month);

    // カレンダーの要素を追加
    wrapper.appendChild(headData);
    wrapper.appendChild(bodyData);
    document.querySelectorAll("td").forEach(function (target) {
        // 引数targetにはdiv要素が1つずつ渡されている
        target.addEventListener('click', handler);
    });
}


いちおうこう書いたものの、カスタムデータ属性などを使って、inputに設定したい値をtdにもっておいたほうがいい気がします。
(もちろん、年月を表示しているところから取ってもいいんですが)

querySelectorを雑につかってるので、クラスとかタグ名とかで引かずにすむように、取りたい場所やセットしたい場所には適切なidを付与することを推奨します。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/01/17 19:45

    なるほど。私自身で月が変わっても月日を取得できるようにいろいろと試してみたのですが出来ませんでした。
    もし可能であればどのようにしたらいいかアドバイスを頂くことはできないでしょうか?

    キャンセル

  • 2019/01/18 08:46 編集

    答え書き換えてます。その書き換えた答えで、こちらでは動く、という意味のコメントです。もう一度回答からコピペしてみて動きませんか?
    この書き換えた答えがアドバイスです。

    キャンセル

  • 2019/01/18 16:07

    ありがとうございました。デフォルト時のinputを今日の日付に表示させようとしていてコードを色々いじっていたのでうまく動かなかったのですが、提示していただいとコードに一旦全て戻したら動きました。
    おそらくhandler関数でクリックされた時の日付をinputに入れているのかなと思うので、関数内で何もクリックしていない時は今日の日付をinput内に表示させるにはどうしたらいいのでしょうか?
    愚策でwind.onload内に今日の日付を表示させるためにだけだらだらとコードを書いて、最後に
    document.getElementById("today").value = ymd;
    にして今日の日付を表示させたのですが、もしもっと簡単に書ける方法があればご教授して頂けないでしょうか?

    キャンセル

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

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