「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のインストール
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.log
でlistName
を表示するだけにしておきます。
# app/assets/javascripts/controlelrs/TodoListCtrl.coffee ... $scope.listNameEdited = (listName) -> console.log(listName)
では、Todoリスト画面を表示し、タイトルをクリックすると次のように編集ができます。
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_lists
のupdate
のルーティングがないので、ルーティングを修正します。
# 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に保存されています。
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の内容も編集可能になりました。
以上です。