2018/01/31

[Vue.js]ページ内の全フィールドを監視し変更されたらイベントを発火する(deep watch)

設定ページの設定内容が変更されたら自動的に保存。検索フォームで条件を追加したら自動的に検索。このようにユーザがボタンを押下しなくても、changeイベントで自動的に処理してくれるアプリケーションをよく見かける。

ただ実際やろうとすると、すべてのフィールドにchangeイベントを登録し、変更されたかどうかを監視させなければならないので面倒だ!
もっと良い方法はないかとvueの公式ドキュメントを読んでいたら良さそうなものを見つけたので、実例を交えて紹介する。


↓こんな感じの検索フォームを例に紹介する。
※ 当記事では使っているバージョンはvue@2.x系(2.5で動作確認)

watchをつかってフィールドを監視し、変更されたらイベントを発火する


普通に全フィールドをwatchするのは手間なので、formオブジェクトを使って1つにまとめる。ただ、オブジェクトをwatchしても下の階層が変更されたかどうかは監視できないので、{ deep: true }指定することでオブジェクトを監視できる。
<main id="app">
  <form>
    <div>
      <label>Title</label>
      <input type="text" v-model="form.title">
    </div>
    <div>
      <label>Status</label>
      <label>
        <input type="checkbox" value="done" v-model="form.status">
        DONE
      </label>
      <label>
        <input type="checkbox" value="progress" v-model="form.status">
        PROGRESS
      </label>
      <label>
        <input type="checkbox" value="todo" v-model="form.status">
        TODO
      </label>
    </div>
  </form>
  <table>
    <thead>
      <tr>
        <th>Title</th>
        <th>Status</th>
      </tr>
    </thead>
    <tbody>
      <tr
        v-for="(todo, i) in filteredTodos"
        :key="i"
      >
        <td>{{ todo.title }}</td>
        <td>{{ todo.status }}</td>
      </tr>
    </tbody>
  </table>
</main>
// import vue@2.5
const todos = [
  { title: 'test1', status: 'done' },
  { title: 'test2', status: 'progress' },
  { title: 'test3', status: 'todo' },
  { title: 'test4', status: 'done' },
  { title: 'test5', status: 'progress' },
  { title: 'test6', status: 'todo' }
]

new Vue({
  el: '#app',
  data () {
    return {
      todos: todos,
      filteredTodos: [],
      form: {
        title: '',
        status: ['done', 'progress', 'todo']
      }
    }
  },
  watch: {
    // formオブジェクト内のすべての変更を監視する
    form: {
      handler (val, old) {
       this.search()
      },
      deep: true
    }
  },
  created () {
    this.filteredTodos = this.todos.slice()
  },
  methods: {
    search () {
      // APIコール(GET /todos)
      setTimeout(() => {
        // 検索
        this.filteredTodos = this.todos.slice().filter(a => {
          const isMatchedTitle = this.form.title ? a.title.includes(this.form.title) : true
          const isMatchedStatus = this.form.status.includes(a.status)
 
          return isMatchedTitle && isMatchedStatus
        })
      }, 500)
    }
  }
})
formオブジェクトにtitle、statusを追加し、それを入力フィールドにバインドする。
そしてwatchでhandlerとdeep: trueを指定すればOK。

これでformオブジェクト内のいずれかが変更されるとhandlerが実行され、this.searchメソッドを呼ぶことができる。



参考サイト







以上

written by @bc_rikko

0 件のコメント :

コメントを投稿