Knockout.jsを使って実装してみた
背景
業務でwebサイトの古い画面を改修する際、knockout.jsを使って1機能実装したので、調べた内容やどう対応したかをまとめました。
Knockout.js
一言でいうと、「MVVM(Model-View-ViewModel)パターンをサポートしたJavaScriptフレームワーク」です。
MVVMの良い点の一つは、ViewとViewModel間でデータをバインドできることです。
- ViewModel(状態オブジェクト)をView(HTML側)に反映させる
- Viewの変更をViewModelに反映させる
View、ViewModelの状態の変化を監視して、データの更新をリアルタイムで行います。
View、ViewModelのバインドを手動でやるとすると、DOMの取得、更新、反映の処理を記述する必要があり大変ですが、MVVMは自動で行ってくれるので楽です。
Knockout.jsは上記をjavascriptで書けるのでフロントエンドで結構人気が出たそうです。
knockout.jsの特徴
- エレガントな依存トラッキング
データモデルが変更される度に、UIの関連付けられた部分を更新します。 - 宣言型 バインディング
データモデルとUIを関連付ける、シンプルで明確な方法です。複雑な動的UIも、バインディング・コンテキストを階層化させることで簡単に作成できます。 - 拡張が容易
新たなバインディングの仕組みを実装することも、最小限のコード量で実現できます。
引用: http://kojs.sukobuto.com/docs/introduction
実装した機能
年月入力フォームをテキスト入力フォームからプルダウンに変更する実装をしました。
// before
<input type="txet" ... />
// after
<input type="month" ... />
要件:
- 初期値を任意の値で設定する
- 空文字の場合はプルダウンの下にエラー文言を表示する
完成したコード
<input type="month" name="yearMonth" data-bind="value: yearMonth, message: yearMonthMessage" class=" js-yearMonth" />
// 初期値設定用
self.yearMonthMessage =
ko.observable($('.js-yearMonth')
.val(`${任意の値}-03`))
// 入力データバインド用
self.yearMonth =
ko.observable($('.js-yearMonth').val())
※既存コードがjQueryを使用しているため、jQueryのコードも含まれます
※selfは、親コンポーネントで定義したViewModalのインスタンスが渡されます。
実装で困ったこと
初期値設定処理と、入力データ用の処理を一つにまとめる事ができず対応に時間がかかりました。
value: yearMonth
を使用し、初期値の設定と、入力データの監視を行おうとしましたが、どちらか片方の処理しか正確に動作せず、対応策として、処置を分けることにしました。
分けることで、データ送信する時、どの値を送信するのかややこしくなりましたが、初期値を設定した後に、self.yearMonth
の処置で一度初期値の値を取得しているのでyearMonth
の値を送信することで一通り要件を満たす事ができました。(val()の動きが関わってきます)
参考: https://js.studio-kingdom.com/jquery/attributes/val
さいごに
1機能しか実装してませんが、knockout.jsについて調べることからスタートしたので3人日くらい時間かかってしまいました。実装出来たときの喜びは大きかったです。
knockout.jsが気になった方は是非調べてみて下さい。
参考:
Discussion