Ext JS に関しては,新しい記事は Sunvisor Lab. ExtJS 別館 にあります。そちらもよろしくお願いいたします。
Ext Direct での更新処理
Ext Directでの更新処理をやってみたいと思いました。やっぱりExtJSらしいところで,GridPanel(いや更新ですからEditorGridPanelか)で訂正したデータをサーバーに更新をかけるということになります。
サーバーサイドのxFrameworkPXのモデルに更新用のメソッドを用意して,DirectStoreのapiにそれをセットするのかなと思ったのですが,apiの仕様がいまいちよくわかりません。パラメータの渡し方も。ですので,更新をStoreに任せるのではなくて,違う方法での実現を考えました。
※ その後,勉強の甲斐あって,Storeに任せる方法もわかりました。こちらを参照ください>08.DirectStore でサーバー更新をかける
JavaScript側での更新タイミング
更新をかけるタイミングとしてまず注目したのは,Storeのupdateイベントです。データの更新があったらこのイベントが発生します。このイベントで更新をかけてはどうかと考えました。
EditorGridPanelに結びつけられたStoreでのupdateイベントは,Gridのセルが変更されたときに発火します。その際にoperationには,Ext.data.Record.EDITがセットされます。また,StoreのcommitChangesがコールされたときにも発火します。その際には,operationは,Ext.data.Record.COMMITが渡されます。また,このイベントにはStoreとRecordが渡されます。
operationがExt.data.Record.EDITの時のイベントでサーバーを更新する方法もありですが,すべての更新を終えて「保存」ボタンをクリックしたようなときに更新をかけたいと思います。ですので,「保存」ボタンをクリックしたらStoreのcommitChangesをコールして,updateイベントでサーバーを更新させようと考えました。
複数のレコードが更新されてCOMMITされた時に,どんな動作をするのでしょうか。更新されたレコード数だけupdateイベントが発生するのでしょうか。違います。一度だけしか発生しません。そのときのrecordは最後に更新されたレコードだけがセットされています。ではStoreのgetModifiedRecordメソッドで更新されたレコードを得て,それを対象に更新しましょう。とおもいきや,updateイベントが発生するのは,すでにStoreがコミットされた後みたいで,getModifiedRecordメソッドで返ってくるレコードは空っぽでした。
ですので,updateイベントで処理するのではなく,「保存」ボタンのclickイベントハンドラの中でStoreをサーバー側に転送する処理を書くことにします。
Storeの中での更新されたレコードを得るには,さきほどから出てきているgetModifiedRecordメソッドを使います。戻り値はrecordの配列です。さらにレコードの中の更新されたフィールドを得るには,recordのmodifiedプロパティで得られますよとAPIドキュメントに書いてあります。modifiedは変更されたフィールド名をキーにして変更前の値を値として持ちます。recordのdataプロパティとこのmodifiedプロパティを使えば,更新されたレコードとフィールドをサーバー側に伝えることができそうです。
と,いま,APIドキュメントを参照していたら,recordには,getChanges()というメソッドもあります。こちらはそのものずばりで,変更されたフィールド名と変更後の値のセットが得られるようです。そこで,サーバー側には,RecordのidとgetChanges()で得られたオブジェクトを渡したらいいんじゃないでしょうか。JavaScript側のソースです。Saveボタンが押されたときのイベントハンドラです。
onBtnSaveClick: function(button, e) { var store = Ext.StoreMgr.get('StaffStore'); var mrec = store.getModifiedRecords(); var changed; var rowId; for(var r=0; r < mrec.length; r++){ changed = mrec[r].getChanges(); rowId = mrec[r].id; // サーバーサイド関数を呼び出す Staff.updateRec(rowId, changed); } store.commitChanges(); },
getModifiedRecordsで変更のあったレコードを取り出し,それぞれのレコードについて,サーバー側のメソッドupdateRecを呼び出しています。その際に渡しているのが,Record.idとgetChanges()の戻り値です。結構簡単なハンドラになりましたね。
サーバー側のモジュールのメソッドです。
public function updateRec($id, $changedData) { // 引数を連想配列にキャスト $updateData = (array)$changedData; // データの更新 $this->set( $updateData, array('id' => $id) ); }
xFrameworkPXのモジュールのsetメソッドは,更新するフィールド名と値のセットを渡すので,ExtJSのgetChanges()メソッドの戻り値がそのままんま使えます。だからメソッドは上記のように超簡単な記述で済みます。すごい!簡単!かっこいい!
なお,渡された$changeDataは,stdClassとして渡されるので,4行目で連想配列にキャストしています。
いろいろ試行錯誤しましたが,最終的には非常にスマートな感じで更新部分ができました。これもxFramewordPXのおかげですね。