5

に付随する(一部のブラウザで提供されるデフォルトのカレンダー日付ピッカーを置き換える)カレンダーピッカーを作成していinputますtype="date".

「単純さ」のために、Chrome (およびおそらく他のブラウザー) の日付入力では無効な日付を入力できますが、検証に失敗することが文書化されています (つまり、2017 年 6 月 31 日を入力できますが、" 」)。

私の質問は: 入力に無効な日付が入力された場合、無効な日付の値を取得するにはどうすればよいですか?

var date_input = document.getElementById('date_input');
var output_div = document.getElementById('output_div');

output_div.innerHTML = date_input.value;

date_input.addEventListener('input', function(e){
	output_div.innerHTML = e.target.value;
});
<p>To quickly input an invalid date, select the day field and press the down arrow (on Chrome OSX this displays an empty div below the input instead of the invalid date). This will select 31/06/2017</p>
<input type="date" value="2017-06-01" id="date_input" />
<br />
<br />
<div id="output_div" />

4

1 に答える 1

3

このようではない

var date_input = document.getElementById( 'date_input' );
var output_div = document.getElementById( 'output_div' );

output_div.textContent = date_input.valueAsDate; // :-)

date_input.addEventListener( 'input', function( evt ){
    var val = date_input.value,
        sel = document.getSelection();
    if ( date_input.validity.badInput ) {
        // date_input.focus(); // with or without this,
        // date_input.select(); // this doesn't work but,
        // due to the added <span> wrapper:
        sel.selectAllChildren( date_input.parentElement );
        // this does. So:
        val = sel.toString() || function() {
            var copied = document.execCommand( 'copy' );
            sel.empty(); // clear the selection
            return "Invalid date" + ( copied ? " copied to clipboard." : "" );
        }();
    }
    output_div.textContent = val;
});
#output_div {
    margin-top: 1em;
}
<p>To quickly input an invalid date, select the day field and press the down arrow (on Chrome OSX this displays an empty div below the input instead of the invalid date). This will select 31/06/2017</p>
<span><input type="date" value="2017-06-01" id="date_input"></span>
<div id="output_div"></div>

明らかに、value示されているのは実際にはのシャドウ DOM出力であり、 のシャドウDOMにアクセスできないため、目に見える値は事実上 JS には不明です。 <input>user-agent

アクセシビリティ上の理由から、visible 値はスクリーン リーダーなどからアクセスできる必要があり、手動でクリップボードにコピーすることもできます。

テキストをプログラムで選択してコピーする方法を複数試してみましたが、アイデアと忍耐力が尽きて、クリップボードにコピーすることしかできませんでした。

  • 他の誰かが のaria-value*属性#shadow-root (user-agent)を JS で読み取る方法を理解できれば、先に進むことができます。
  • 他の誰かがselection文字列をに割り当てる方法を理解できる場合varは、別の方法があります。

でも

無効な入力は予測可能な範囲外に制限されているため、無効なものvalueに変更される前に最後に有効だったものを監視し、それが確実に現在あるべき値を計算できます。

  • 日付ピッカーを使用する場合、すべての入力が有効になります。
  • 入力する場合は、キーストロークを監視します。
  • 矢印ボタンを使用していて、日付が30/06/2017無効になる変更前であり29/06/201730/05/2017、 、30/07/201730/06/2016および30/06/2018がすべて有効である場合、無効な日付は である必要があります31/06/2017

私はその作業を (まだ) 実験していませんが、できると確信しています。私はこの答えでその解決策を投稿しますが、私の一日の半分はすでにこの質問に飲み込まれていて、お腹がすいています. 誠実な関心が示された場合は、喜んでコードを提供します。

それでもだめ

矢印ボタンを使用して作成された場合、無効な日付が表示され、最後の日付が有効であった場合にのみ表示されます。おそらくそれを回避する方法を見つけることができましたが、公式にはあきらめました!人生短し。

MDN によると:

... 表示される日付形式は、ユーザーのオペレーティング システムの設定ロケールに基づいて選択されます。

これにより、キーストロークの追跡が不当に重要になります。

<input type="datetime-local">ただし、その問題を解決する可能性があり、他の問題を解決できる可能性があることを発見しました。

したがって、これは何か便利です:

しかし、これを強制的に機能させようとすると、通常は収まらない場所にスイカを挿入しようとしているように感じ始めます。

魅力がほとんどまたはまったくないハムフィストのクラッジであり、誰かがそれを強く見すぎると壊れそうです. これまでで最高の免責事項;)

var date = "",
    input = document.querySelector( "input" ),
    output = document.querySelector( "output" ),
    bits = function( d ) {
        return [ d.getFullYear(), d.getMonth() + 1, d.getDate() ];
    },
    adjustedDate = function( o ) {
        var d = new Date( date ),
            b = bits( d ),
            year = b[ 0 ],
            month = b[ 1 ],
            day = b[ 2 ];
        switch ( o.i ) {
            case "d": return [ year, month, ( day + o.v ) || 31 ];
            case "m": return [ year, month + o.v, day ];
            case "y": return [ year + o.v, month, day ];
        }
    },
    calcDate = function() {
        var ad, vd, rd;
        [ { i: "d", v: 1 },
          { i: "d", v: -1 },
          { i: "m", v: 1 },
          { i: "m", v: -1 },
          { i: "y", v: 1 },
          { i: "y", v: -1 }
        ].forEach( ( v ) => {
            ad = adjustedDate( v ).join( "-" );
            vd = bits( new Date( ad ) ).join( "-" );
            if ( ad !== vd ) {
                rd = ad;
            }
        } );
        return rd.split( "-" ).map( ( v ) => {
            v = v.toString();
            return v.length === 1 ? "0" + v : v;
        } ).join( "-" ); // tired so mental
    },
    showDate = function() {
        output.textContent = date = ( input.value || calcDate() );
    };
showDate();
input.addEventListener( "input", showDate, false );
output {
    margin-left: 1em;
}
<p>To quickly input an invalid date, select the day field and press the down arrow. This will select 31/06/2017 and output the desired invalid date string.</p>
<form><input type="date" value="2017-06-01"><output></output></form>

于 2017-06-20T10:54:07.397 に答える