Jquery timepickerで別フィールドに+15分した値を表示したい
解決済
回答 1
投稿
- 評価
- クリップ 0
- VIEW 1,253
前提・実現したいこと
現在、jquery timepickerというタイムピッカープラグインを使用しております。
ライブラリ
このプラグインで2つのフィールドを選択するとお互いの時間に応じて、選択されている
時刻が変動するというコードを記述しております。
開始時刻は終了時刻より後に絶対ならないように動いています。
発生している問題・エラーメッセージ
現在のままのコードだと、開始時刻が終了時刻を上回って入力されると
開始時刻=終了時刻になるようになっており、出来れば終了時刻の15分前になるようにしたいです。
該当のソースコード
$(function () {
$("#timepicker_b").timepicker({
timeFormat: 'HH:mm',
interval: 15,
minTime: '8.3',
maxTime: '19:00pm',
dynamic: false,
dropdown: true,
scrollbar: true,
change: function(time) {
var b = $("#timepicker_a");
var instance = b.timepicker();
instance.option('minTime', time);
instance.option('defaultTime', time);
if (b.val() < this.val()) {
b.val(this.val());
$("#timepicker_a").prop('disabled', false);
}
}
});
$("#timepicker_a").timepicker({
timeFormat: 'HH:mm',
interval: 15,
minTime: '8.3',
maxTime: '19:00pm',
dynamic: false,
dropdown: true,
scrollbar: true,
change: function(time) {
var a = $("#timepicker_b");
var instance = a.timepicker();
instance.option('defaultTime', time);
if (a.val() > this.val()) {
a.val(this.val());
var b = $("#timepicker_a");
var instance2 = b.timepicker();
instance2.option('minTime', time);
b.val(this.val());
}
}
});
});
ご存知でしたらご教授いただけると幸いです。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
こんにちは
timepicker
を初期化するときに与えるchange
コールバックの引数 time
には、Dateオブジェクトが入ってきます。これを踏まえてご質問の主旨としては、
- Dateオブジェクトである
time
で与えられる時刻に 15分を加えた時刻を求めて、さらに表示形式の文字列に変換するにはどうしたらいいか?
ということかなと思われました。以下、これに対する回答になります。
与えられた時刻に何らかの時間を加えたり引いたりしたいというときは、Moment.js の add やsubtractを使うとすっきり書けます。また、formatを使えば様々な形式の文字列へ変換できます。
例えば、Dateオブジェクトtime
で与えられる時刻に 15分を加えた時刻を HH:mm
形式の文字列にしたいときは以下のようにすれば得られます。
moment(time).add(15, 'minutes').format('HH:mm')
サンプルを挙げておきます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Q193894</title>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/timepicker/1.3.5/jquery.timepicker.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/timepicker/1.3.5/jquery.timepicker.min.css">
<style>
input, div { font-size: 16pt; }
span { color: red; }
</style>
<script>
$(function(){
$("#timepicker").timepicker({
timeFormat: 'HH:mm',
interval: 15,
minTime: '8.3',
maxTime: '19:00pm',
dynamic: false,
dropdown: true,
scrollbar: true,
change: function(time) {
$('#after15min').text(moment(time).add(15, 'minutes').format('HH:mm'));
$('#before30min').text(moment(time).subtract(30, 'minutes').format('HH:mm'));
$('#after1andAHalfhours').text(moment(time).add(1.5, 'hours').format('HH:mm'));
}
});
});
</script>
</head>
<body>
<input id='timepicker' />
<ul>
<li>15分後: <span id="after15min" /></li>
<li>30分前: <span id="before30min" /></li>
<li>1.5時間後: <span id="after1andAHalfhours" /></li>
</ul>
</body>
</html>
上記のサンプルでは、timepicker
から時刻を選ぶと、その時刻に対して、15分後、30分前、1.5時間(90分)後の時刻を求めて HH:mm
形式の文字列として、以下のように表示されます。
以上、参考になれば幸いです。
追記
上記で説明した Moment.js を使って、開始時刻と終了時刻の入力に timepicker
を使い、開始時刻が終了時刻を越えるような選択をした場合に、開始時刻を終了時刻の15分前に修正するサンプルを作成しました。
開始時刻:<input class="timepicker start" />
〜
終了時刻:<input class="timepicker end" />
$(".timepicker").timepicker({
timeFormat: 'HH:mm',
interval: 15,
minTime: '08:30',
maxTime: '19:00',
dynamic: false,
dropdown: true,
scrollbar: true,
change: function(time) {
const start = moment($('.start').val(), 'HH:mm');
const end = moment($('.end').val(), 'HH:mm');
if (start.isAfter(end)) {
$('.start').val(end.subtract(15, 'minutes').format('HH:mm'));
}
}
});
- 動作確認用 jsFiddle: https://jsfiddle.net/jun68ykt/j9ntco13/4/
このサンプルでは、 開始時刻、終了時刻、いずれを変更した場合にも、開始時刻が終了時刻を越えていたら開始時刻を終了時刻の15分前に変更します。また、 change
コールバックに渡される引数time
は使用しませんでした。
上記のように、Moment.js を使うと、ある時刻(日時)がある時刻(日時)の後であることの判定に、 isAfter というような、より自然な名前のメソッドで比較することができます。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.19%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2019/06/09 16:49
まさに、私の望んでいる内容でサンプルまでつけていただきありがとうございました。
教えていただいたサンプルから、最後の一文のところを
if (start.isAfter(end)) {
$('.end').val(start.add(15, 'minutes').format('HH:mm'));
}
に書き換えたら一番理想の形となりました!
ですが、一番最初にページを開いたタイミングで開始時間を変更すると
if (start.isAfter(end)) が発動しなかったので現在検証中です。
2019/06/09 17:06
> まさに、私の望んでいる内容
とのことでよかったです。
> 一番最初にページを開いたタイミングで開始時間を変更
すると、終了時刻には何も入っておらず、その場合
const end = moment($('.end').val(), 'HH:mm');
によって、 end は undefined や nul lにはならずに、 日時として無効な値を保持する
Momentオブジェクトが入り、その場合
start.isAfter(end)
をふくめ、 end を使った比較判定はどれも false を返します。
Momentを使えば、時刻(あるいは日時)の処理がかなり楽に行えると思いますので、質問者さまの要件にあわせて色々、試してみて頂ければと思います。
2019/06/09 18:12 編集
Moment の便利なメソッドで、もうひとつ、 isValid というのがあります。
変数 x が、有効な日時を保持するmomentオブジェクトであるとき、
x.isValid()
は true になります。( FYI: https://momentjs.com/docs/#/parsing/is-valid/ ) 逆にこれが false のとき x は日時として無効な値が入っています。
これを使って、先のサンプルで、if 条件を
if (start.isAfter(end) || !end.isValid()) {
・・・
}
とすれば、初期状態で終了時刻が選ばれてない状態で開始時刻を選んだときも、if 条件が true になって、終了時刻が設定されます。
2019/06/09 18:20
あとは同じ時刻の時もendを15分送らせたいのと、endから入力した際にはstartが15分前に表示させるというのを同時にやりたいです
2019/06/09 18:30 編集
$('.end').val(start.add(15, 'minutes').format('HH:mm'));
}else{
if (start.isAfter(end) || !end.isValid()) {
$('.end').val(start.add(15, 'minutes').format('HH:mm'));
}
}
で前者はいけました!
2019/06/09 18:40 編集
Momentには、「等しいか後」あるいは「等しいか前」のためのメソッドが用意されています。
2つのMomentオブジェクト a, b があったときに、
a は b と等しいまたは後である: a.isSameOrAfter(b) が true
👉 FYI: https://momentjs.com/docs/#/query/is-same-or-after/
a は b と等しいまたは前である: a.isSameOrBefore(b) が true
👉 FYI: https://momentjs.com/docs/#/query/is-same-or-before/
上記の isSameOrAfter を使い、
> endから入力した際にはstartが15分前に表示させる
もあわせてやるとしたら、たとえば以下のようになるかと思います。
https://jsfiddle.net/jun68ykt/j9ntco13/7/
ちょっと if 条件が込み入ってきたので、もう少し短いコードにリファクタできるかもしれません。
2019/06/09 18:41
👏 はい。それでもOKです!
2019/06/09 20:04
やりたかったこと全て解決しました。
Momentのドキュメントだけでかなりの量があるので、把握するまで大変そうです^^;
現状はこちらで実装して今後勉強しつつリファクタ出来たらと思います。
ありがとうございました!
2019/06/09 21:05
そういって頂けると回答者冥利に尽きます。
それと、もうひとつだけお節介といいますか、以下をちょっとお遊びで作ってみました。
https://jsfiddle.net/jun68ykt/j9ntco13/12/
上記は、
・初期表示のときに、
開始時刻 08:30, 終了時刻 19:00 が選ばれた状態で表示され、
かつ、開始時刻の選択肢に、19:00 は表示されず、
かつ、終了時刻の選択肢に、08:30 は表示されない。
・その後、終了時刻をたとえば 14:00 に変更してから、次に開始時刻を変更しようとすると、
終了の15分前の 13:45 までしか選択肢に表示されない。
・次に、開始時刻として、13:00 を選ぶと、終了時刻の選択肢に13:15 よりも前は表示されない。
という動作をさせるコードです。
かなりトリッキーなコードですので、まくまで参考に留めて頂ければと思います。
2019/06/09 21:50
ここから開始時間の下に○時間等のボタンを用意して押せばそれが終了時間に入るとかのプログラムも
面白そうですね!
ありがとうございます^^
javascriptかなりお詳しいようで、もしよろしければ私の回答がついてない質問も見ていただけると嬉しいです・・・!