LoginSignup
0
4

More than 5 years have passed since last update.

Vue.js ElementUIのTimePickerに任意の値を入力する(バリデータの追加)

Last updated at Posted at 2018-03-18

本稿は下記の記事の続きです。
Vue ElementUIのTimePickerに任意の値を入力する
https://qiita.com/at-sea/items/4889ffdac9f70be9c279

リスト要素になっているTimePicker(el-time-select)に対して、バリデーションを実装してみました。なかなかうまく動作せず、数パターン試しました。動かないパターンも含めて掲載します。
解説はコメント文中に埋め込んでいますが、大きなポイントは2つありました。
1. リスト要素にバリデーションを行うために、公式にならい、el-form-itemタグにバリデーションルールを直接書き、propsでindex番号を付与しています。
2. 先の記事に書いたように、el-time-selectでリスト選択する方法と手入力の両方を許容するためにblurイベントの最後に値を書き換えていますが、この後にバリデーションを実行させています。こうしないと、バリデーション→値の書き換えとなってバリデーションが空振りとなります。

<template>
<div>
  <!-- el-form の ref と model でバリデーション対象のモデルを指定しておく -->
  <el-form :rules="rules" :inline="true" ref='scheduleForm' :model='scheduleForm'>
    <el-form-item v-for='(schedule, index) in scheduleForm.scheduleList'>
      ({{index + 1}}日目)
      <!-- DatePicker, TimePicker にリストの番号をidxNumberという属性で付与しておく -->
      <el-date-picker v-bind:idxNumber='index' v-model='schedule.startDate' type='date' :clearable='false' />

      <!-- form-itemタグのpropでvalidatorに渡す属性を付与する。公式サイトの「Delete or add form items dynamically
」を参考に。 -->
      <!-- 入力チェックは、必須チェックと、時刻形式の2つをチェック -->
      <!-- 入力チェックルールはここに書かないと、validatorに値を渡すことができなかった。 -->
      <!-- form-itemタグに書かない方法もあるのかもしれないが、分からなかった。 -->
      <el-form-item :prop="'scheduleList.' + index + '.startTime'" :rules="[
       {required: true, message: '入力してください'},
       {pattern: /^([01]?[0-9]|2[0-3]):([0-5][0-9])$/, message: '時刻形式[00:00~23:59]で入力してください'}
      ]">
        <el-time-select v-bind:idxNumber='index' v-model='schedule.startTime' @blur='inputToStartTime' :clearable='false' /> -
      </el-form-item>

      <!-- これだとValidatorは呼べるが値が渡せていないため、常にNotNull状態になる -->
      <el-form-item :prop="'scheduleList.' + index + 'endTime'">
        <el-time-select v-bind:idxNumber='index' v-model='schedule.endTime' @blur='inputToEndTime' :clearable='false' />
      </el-form-item>

      <!-- 開始終了のコンポーネントもちょっと試してみる -->
      <el-form-item prop="startEndTime">
        <el-time-picker is-range v-model="schedule.startEndTime" range-separator="-" start-placeholder="Start time" end-placeholder="End time" format='HH:mm'>
        </el-time-picker>
      </el-form-item>
    </el-form-item>

    <!-- 参考までに基本パターン -->
    <div>
      <el-form-item prop="start">
        <el-time-select v-model='scheduleForm.start' :clearable='false' @blur='inputToStart' />
      </el-form-item>
    </div>
  </el-form>
  <el-col>{{scheduleForm}}</el-col>
</div>
</template>

<script>
export default {
  data() {
    var checkTime = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('入力してください'));
      }
      // 正規表現による書式チェック
      if (!value.match(/^\d{2}\:\d{2}$/)) {
        callback(new Error('時刻形式[HH:mm]で入力してください'));
      }
      var vHour = value.substr(0, 2) - 0;
      var vMinutes = value.substr(3, 2) - 0;
      if (vHour < 0 || vHour > 23 || vMinutes < 0 || vMinutes > 59) {
        callback(new Error('時刻の範囲が不適切です'));
      } 
      else {
        callback();
      }
    };
    return {
      scheduleForm: {
        scheduleList: [{
            startDate: '2018-03-18',
            startTime: '09:00',
            endTime: '17:00',
            startEndTime: [new Date(2016, 9, 10, 8, 40), new Date(2016, 9, 10, 9, 40)]
          },
          {
            startDate: '2018-03-19',
            startTime: '09:00',
            endTime: '17:00',
            startEndTime: [new Date(2016, 9, 10, 8, 40), new Date(2016, 9, 10, 9, 40)]
          }
        ],
        start: '09:00'
      },
      rules: {
        endTime: [{
            required: true,
            message: '入力してください',
            trigger: 'blur'
          },
          {
            pattern: /^([01]?[0-9]|2[0-3]):([0-5][0-9])$/,
            message: '時刻形式[HH:mm]で入力してください',
            trigger: 'blur'
          }
        ],
        // 基本パターン用
        start: [{      
          validator: checkTime
        }],
        startEndTime: [{      
          type: 'date',
          required: true,
          message: '入力してください',
          trigger: 'blur'
        }]
      }
    }
  },
  computed: {},
  methods: {

    // 引数 componentには、elementUIによってコンポーネント自体(TimePicker)が渡される。
    // _data.userInputには、ユーザ入力値が入っている。
    // _date.valueOnOpenには、ピッカーで選択した値が入っている。
    // 手入力・ピッカーでの選択により、userInputとvalueOnOpenどちらかに値が入り、もう一方はNullのよう。
    // TimePickerはstepに設定された値単位に補正してmodelにバインドするため、手動で値を代入する。
    inputToStartTime(component) {
      this.scheduleForm.scheduleList[component.$attrs.idxNumber].startTime =
        (component._data.userInput) ? component._data.userInput : component._data.valueOnOpen;
      component._data.valueOnOpen =
        (component._data.userInput) ? component._data.userInput : component._data.valueOnOpen;
      // Formすべてのバリデーションを実行する。開始時間だけのバリデーション実行する方法は不明だった。
      this.$refs.scheduleForm.validate();
    },
    inputToEndTime(component) {
      this.scheduleForm.scheduleList[component.$attrs.idxNumber].endTime =
        (component._data.userInput) ? component._data.userInput : component._data.valueOnOpen;
      component._data.valueOnOpen =
        (component._data.userInput) ? component._data.userInput : component._data.valueOnOpen;
      this.$refs.scheduleForm.validate();
    },
    inputToStart(component) {
      this.scheduleForm.start =
        (component._data.userInput) ? component._data.userInput : component._data.valueOnOpen;
      component._data.valueOnOpen =
        (component._data.userInput) ? component._data.userInput : component._data.valueOnOpen;
      // ここでValidatorを呼ぶ。そうでないと、先にValidatorが動作し、後に本メソッドが実行されるため、Validatorが動作しない。
      // 次にblurイベントが発生したときに古い値を元にValidatorが動作してしまう。
      this.$refs.scheduleForm.validateField('start');
    }
  }
}
</script>

正しく動作するのは、画像中でいうと左から2番目の列、startTimeの部分です。必須チェックと、正規表現による時刻形式(HH:mmであることと、時は0~23、分は0~59であること)をチェックしています。endTimeの方法は動作しません。
picker3.png

0
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
4