読者です 読者をやめる 読者になる 読者になる

Rails Webook

自社のECを開発している会社で働いています。Rails情報やサービスを成長させる方法を書いていきます

RailsでAngularJSを使ってTodoアプリを作成 - 8. AngularJSで編集可能(Editable)なフィールドを作成する

AngularJS Rails中級 連載

f:id:nipe880324:20150112194806p:plain

「RailsでAngularJSを使ってTodoアプリを作成」の連載8回目です。
今回は、AngularJSで編集可能(Editable)なフィールドを作成し、Todoリスト名とTodoの内容を更新できるようにします。


テキストをクリックすると変更可能になり、OK/キャンセルボタンで変更を確定/キャンセルできるようにします。


Editableなライブラリは幾つかあるのですが、マイナーですがUI的にeditablespanを使います。

  • editablespan - Angular用に作られているが、Star数やコミット数からマイナー。UIは悪くはない。
  • Angular-xeditable - Angualr用に作られているので、AngularJSで使いやすい。

仕事で使う場合は、angularjs-xeditableなど他のメジャーなものやコミュニティが活発なものを使い、UIはCSSで変えた方が良いです。


動作確認

  • Rails 4.2.0
  • AngularJS 1.3.8
  • Bootstrap 3.3.1
  • UI Bootstrap 0.12.0
  • ransack 1.6.2
  • kaminari 0.16.1
  • mk-eitablespan 1.0.0

目次

  1. mk-editablespanのインストール
  2. mk-editablespanの使い方
  3. Todoリスト名を編集可能にする
  4. Todo内容を編集可能にする



1. mk-editablespanのインストール

mk-editablespan - GitHubからソースを取得します。

curl https://raw.githubusercontent.com/mkwidzinska/editablespan/master/build/mk-editable-span.min.js > vendor/assets/javascripts/mk-editable-span.min.js


次に、Railsがmk-eitable-span.minを読み込むようにします。
依存関係によりangularjs.minより後ろであり、appより前である必要があります。

// app/assets/javascripts/application.js
...
//= require mk-editable-span.min


そして、AngularJSの依存リストにmk.editablespanを追加します。

# app/assets/javascripts/app.coffee

# AngularJSの設定ファイル
# 依存ライブラリを記述する
app = angular.module('sampleApp', ['ui.bootstrap', 'ngResource', 'ngRoute', 'mk.editablespan'])
...


2. mk-editablespanの使い方

実際に実装する前に、使い方や指定できる属性を確認します。

変更可能なinput要素を配置したい場所に次のようにHTMLを記載します。

<editablespan
  model="item.description"
  on-ready="onReady(item)"
  span-class="info"
  input-class="info-input"
  input-type="email">
</editablespan>


使える属性とその説明は次の通りです。

  • model - 表示したいテキストの変数名を指定
  • on-ready - テキストを保存後に呼ばれるコールバック関数を指定(ENTERキーを押すと保存にされます)
  • span-class - span要素に適用されるCSSクラス名を指定
  • input-class - input要素に適用されるCSSクラス名を指定
  • input-type - input要素のtype属性の値をHTML5で指定(デフォルトはtext



3. Todoリスト名を編集可能にする

では、mk-editablespanを使ってTodoリスト名を編集可能にします。
Todoリスト名({{list.name}})と記載されている箇所をeditablespanを使うように修正します。

<!-- app/views/templates/todo_list.html.erb -->
...
<div class="panel panel-success">

  <div class="panel-heading">
*    <editablespan model="list.name" on-ready="listNameEdited(list.name)"></editablespan>
  </div>
...


Enterキーが押された(保存された)ときのイベントも定義しておきます。
一応なんの値が渡されるか確認するために、console.loglistNameを表示するだけにしておきます。

# app/assets/javascripts/controlelrs/TodoListCtrl.coffee
...
$scope.listNameEdited = (listName) ->
  console.log(listName)


では、Todoリスト画面を表示し、タイトルをクリックすると次のように編集ができます。
f:id:nipe880324:20150123232256j:plain:w480


Enterキーを押すと、on-readyに指定したメソッドが呼ばれ、今の所はconsole.logにより、 変更後のTodoリスト名がJavascriptコンソールに表示されます。



では、実際にサーバーのDBを更新するようにしていきます。

まず、TodoListサービスクラスのupdateメソッドを呼び出すようにします。

# app/assets/javascripts/controlelrs/TodoListCtrl.coffee
...
$scope.listNameEdited = (listName) ->
  @todoListService.update($scope.list, name: listName)


TodoListサービスクラスにupdateメソッドの中身を実装します。

# app/assets/javascripts/services/TodoListService.coffee
...
update: (list, attrs) ->
  new @service(todo_list: attrs).$update {id: list.id}, (-> null), @errorHandler
  # attrs = { name: listName } なので、todo_list: attrs は { todo_list: { name: listName } } となる
  # Controller側で params = { todo_list: { name: listName } } となる


そして、Railsのコントローラーでupdateメソッドを実装します。

# app/controllers/api/todo_lists_controller.rb

before_action :set_todo_list, only: [:show, :update, :destroy]

...

def update
  @todo_list.update(todo_list_params)
  render nothing: true
end
...


Railsのtodo_listsupdateのルーティングがないので、ルーティングを修正します。

# config/routes.rb

# 変更前
resources :todo_lists, only: [:index, :show, :create, :destroy] do

# 変更後
resources :todo_lists, except: [:new, :edit] do


また、Todoリストを表示するときにtodo_listのIDを返していないので、IDを返すようにします。

# app/views/api/todo_lists/show.json.jbuilder
json.id    @todo_list.id
...

では、サーバーを再起動し、動作を確認します。
先ほどのようにTodoリストのタイトルが変更でき、画面を更新しても値が同じなので、値がサーバーのDBに保存されています。
f:id:nipe880324:20150123232328j:plain:w480





4. Todo内容を編集可能にする

Todoリスト名と同様にTodoの内容も編集可能にします。1度実施したのでサクッと行っていきます。

まずは、Todoリスト画面のHTMLを修正します。

<!-- app/views/templates/todo_list.html.erb -->
...
<div class="todo-description">
*  <editablespan model="todo.description" on-ready="todoDescriptionEdited(todo)"></editablespan>
</div>
...


次に、TodoListCtrl.coffeeにメソッドを追加します。

# app/assets/javascripts/controllers/TodoListCtrl.coffee

$scope.todoDescriptionEdited = (todo) ->
  @todoService.update(todo, description: todo.description)


TodoService.coffeeには既にupdateメソッドが定義されており、RailsのTodosControllerにもupdateメソッドが定義されているので完了です。

では、動作を確認してみます。
次のように、Todoの内容も編集可能になりました。
f:id:nipe880324:20150123232414j:plain:w480


以上です。