Rails + jQueryで Edit in Place(その場編集) UI の実装
2013.10.29
基本的な部分はおさえたので そろそろ参考書から離れて 自分でつくってみようかなと思う。
そういうわけで現在は簡単なタスク管理のWebアプリケーションを実装中。
ユーザにストレスが無いよう利便性を高めるために以下のような仕様を実装したい。
【仕様】
1. 項目の既存の属性をクリックしたらテキストエリアに切り替わって編集モード。
2. テキストエリアからフォーカスを外すか、エンターキーを押した場合 更新 ( ただし文字数0の場合は更新せず元に戻す )
3. Escapeキーを押した場合は更新せず元に戻す
疑問に思った事や困った事、以下。
jQueryでupdate?
$.ajax を使う。jQueryの場合はデフォで「PUT」をサポートしてくれているので UPDATEも安心。
そんなわけで最初のajaxの中身は以下のような形になった。
$.ajax({ contentType: "application/json", dataType: "json", type: "PUT", url: "tasks/" + data_id, data: JSON.stringify({title: val}) });
ここで補足すると、data_id は変更を加えるデータのID番号、valは更新する値。
url、typeについては、railsでリソースベースのルーティングをしている場合、 「controller/ID番号/」に対して「PUT」のHTTPリクエストを飛ばしてあげれば良いので上記のような形式に。
contentType を入れないとrails側で何使ってるかわかってもらえないので、「JSONですよ」ということを教えてあげるために入れておく。
data をhashで渡す場合は JSON.stringifyを使用してちゃんとJSON形式にしてあげるのを忘れないように。さもないと MultiJson::LoadError unexpected token というお叱りを受ける。
contentTypeは「サーバに伝える」側だったけれど、dataTypeは「サーバからもらう」データのフォーマットを指定。dataTypeを指定しないと 余計なエラーを吐くことになったり エラーログを大量の重複リクエストで汚したりする羽目になるみたい( こうした不自然な挙動が発生する原因の詳細に関しては調査中。多分JSONデータとしてサーバが渡したものをクライアント側が別のフォーマットとして解釈しちゃうから? )。
なお、tasksに関しては scaffold で作成しており respond_to にフォーマット jsonが指定済みである。
def update @task = Task.find(params[:id]) respond_to do |format| if @task.update_attributes(params[:task]) format.html { redirect_to @task, notice: 'Task was successfully updated.' } format.json { head :no_content } else format.html { render action: "edit" } format.json { render json: @task.errors, status: :unprocessable_entity } end end end
Escキーで元に戻す
jQueryのkeydownイベントで取得。
if( e.keyCode === 27 ){ $(this).closest("h3").html(previous_txt).closest("li").removeClass("on_title"); }
こんな感じで。previous_txtはテキストエリア変換時に格納しておいた編集前のテキスト。on_title は ビューをテキストエリアに差し替えた際、重複してDOMの処理が行われないようにするため追加するクラス。
「エンターキーで更新」でハマった所
keyupイベントで処理すると文字変換の確定の時に押すエンターキーで更新が飛んでしまう!これではあまりに使い勝手が悪い…。
→ keydownイベントに差し替えることで解決。keydownの場合は文字変換確定時のエンターを判断しないらしい。
Written by Nisei Kimura ( 木村 仁星 )