$resource
をModelとして扱いたい.
そうするとビジネスロジックをメソッドとして生やしたくなる.
ここではname
,email
を属性としてもつUser
Modelについて考える.
(ぼくは普段CoffeeScriptを利用していますので,サンプルもそれでいきます)
下準備
Moduleを作る
第2引数を与えると新規に作成(省略すると既存のが返ってくる).
angular.module 'SampleApp', ['ngResource']
Modelを作る(基本形)
DIしたらUser
(実態は生成されたResource
)が注入される.
User = ($resource) ->
url = '/api/users/:id.json';
defaultParams = { id: '@id' }
actions = {}
$resource(url, defaultParams, actions)
app = angular.module 'SampleApp'
app.factory 'User', [
'$resource'
User
]
Controllerをつくる
さきほどのUser
を注入し,/api/users
からユーザの一覧を取ってきている.
class UsersController
constructor: (@$scope, @User) ->
@users = @User.query()
submit: (user) ->
console.log 'Not yet implemented.'
app = angular.module 'SampleApp'
app.controller 'UsersController', [
'$scope'
'User'
UsersController
]
Viewをつくる
ユーザの一覧,name
とemail
の更新フォームを生成してる.
<ul ng-controller="UsersController as ctrl">
<li ng-repeat="user in ctrl.users">
<label>
name: <input ng-model="user.name">
</label>
<label>
email: <input ng-model="user.email">
</label>
<button ng-click="ctrl.submit(user)">送信</button>
</li>
</ul>
リクエストを飛ばすメソッドを生やす
ここから本題.
たとえばPATCH
,更新処理とかに使うやつですね.
標準だと$resource
から生えてこないので,オプションとして与えてあげましょう.
User = ($resource) ->
url = '/api/users/:id.json';
defaultParams = { id: '@id' }
actions = {
update: { method: 'PATCH' }
}
$resource(url, defaultParams, actions)
Users#$update()
が生えているので,それ呼び出したらPATCH
メソッドで送られる.
便利だ.
class UsersController
# 省略
submit: (user) ->
user.$update()
それ以外のビジネスロジック
たとえばValidation?
ここでは簡単に,"name
及びemail
は空になってはならない"というものについて考える.
Railsで言うとこんなかんじ.
class User
include ActiveModel::Model
attr_accessor :name, :email
validate :name, presence: true
validate :email, presence: true
end
実際の実装.
user.validate()
で結果をboolで返すだけのもの.
(これぐらいだとビジネスロジックとは言わないか…)
User = ($resource) ->
url = '/api/users/:id.json';
defaultParams = { id: '@id' }
actions = {
update: { method: 'PATCH' }
}
User = $resource(url, defaultParams, actions)
angular.extend User.prototype,
validate: ->
@name? && @email?
class User < $resource()
したいところなんだけど,これには問題がある.
実は,レスポンスは必ずResource
でラップされてしまう(ngResource 591行目付近参照).
ということで,$resource()
の生成物(=Resource
)のprototype
をangular.extend()
で拡張してメソッドをぶち込んでる.
かなしみ.
if (action.isArray) {
value.length = 0;
forEach(data, function(item) {
if (typeof item === "object") {
value.push(new Resource(item));
} else {
value.push(item);
}
});
}