テキスト入力フィールド付きTimePickerで秒を非表示にする


概要

Vue.jsにてBootstrapのTimePickerを利用しているときの話です。
サンプルコードはVue.js前提ですが、論じている機能としてはBootstrap自体の話です。

TimePickerで、「秒を非表示にする」方法を説明します。
これ自体は、属性「show-seconds」を外すことで実現できます。

ref. https://bootstrap-vue.org/docs/components/form-timepicker#enabling-of-seconds-spinbutton

問題は、TimePickerに「任意の入力フィールド(直接入力したい要求のため)」を設けている場合です。この時、TimePickerが返却する値は「秒を含む」ため、「入力フィールドに秒が表示」されてしまいます。その際の解決方法を述べます。

※なお、UIをブラウザ依存にして構わないのであれば、Input要素のtime型を利用した方が楽です。
 そちらは標準が「秒は非表示(任意で追加)」なので。

ref. https://bootstrap-vue.org/docs/components/form-input
ref. https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/time

対処方法

「TimePickerに任意の入力フィールドを設けている」とは、
たとえば、次のように実装している場合です。

<div class="div-timepicker">
    <b-input-group class="mb-2">
        <b-form-input
            :id="idOfTimeInput"
            v-model="timeCurrent" 
            v-bind:state="isTimeCurrentValid" 
            type="text" 
        ></b-form-input>
        <b-input-group-append>
            <b-form-timepicker 
                v-model="timeCurrent" 
                button-only 
                right 
                locale="ja"
                :aria-controls="idOfTimeInput"
            ></b-form-timepicker>
        </b-input-group-append>
    </b-input-group>
</div>

ref. https://bootstrap-vue.org/docs/components/form-timepicker#button-only-mode

このとき、b-form-timepickerの戻り値は「HH:MM:SS」の形式となります。

ref. https://bootstrap-vue.org/docs/components/form-timepicker#v-model-return-value

このため、b-form-inputの値は「HH:MM:SS」の形式に更新されてしまい、「秒が表示」されてしまいます。

この現象は、次の2つを行うことで回避できます。

  • b-form-input要素側にbindする変数を別にする
  • 別とした変数のgetter/setterタイミングで「秒の削除」と元のpicker側の変数との同期をする

本サンプルでは「timeCurrent」に代わって「timeCurrentInput」を設け、そのgetter時にtimeCurrentから取得することで同期し、setter時にtimeCurrentへも反映することで、同期します。

<div class="div-timepicker">
    <b-input-group class="mb-2">
        <b-form-input
            :id="idOfTimeInput"
            v-model="timeCurrentInput" 
            v-bind:state="isTimeCurrentValid" 
            type="text" 
        ></b-form-input>
        <b-input-group-append>
            <b-form-timepicker 
                v-model="timeCurrent" 
                button-only 
                right 
                locale="ja"
                :aria-controls="idOfTimeInput"
            ></b-form-timepicker>
        </b-input-group-append>
    </b-input-group>
</div>
computed : {
    timeCurrentInput: {
        get: function () {
            return (this.timeCurrent && this.timeCurrent.length > 5) ? this.timeCurrent.substr(0,5) : this.timeCurrent;
        },
        set: function (newTime) {
            this.timeCurrent = (newTime && newTime.length == 5) ? newTime + ":00" : newTime;
        }
    },
}

以上です。

P.S. 本当にこんな解決方法で良いの?もっとスマートな方法(input要素側にオプション付けるだけ、とか)があるのでは?