LoginSignup
25

More than 5 years have passed since last update.

【AngularJS】$resourceからメソッドを生やす - ぼくが考えたngResourceべすとぷらくてぃす

Last updated at Posted at 2014-12-16

$resourceをModelとして扱いたい.
そうするとビジネスロジックをメソッドとして生やしたくなる.

ここではnameemailを属性としてもつUser Modelについて考える.

(ぼくは普段CoffeeScriptを利用していますので,サンプルもそれでいきます)

下準備

Moduleを作る

第2引数を与えると新規に作成(省略すると既存のが返ってくる).

sample_app.js.coffee
angular.module 'SampleApp', ['ngResource']

Modelを作る(基本形)

DIしたらUser(実態は生成されたResource)が注入される.

user.js.coffee
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からユーザの一覧を取ってきている.

users_controller.js.coffee
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をつくる

ユーザの一覧,nameemailの更新フォームを生成してる.

users/index.html
<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.js.coffee
User = ($resource) ->

  url = '/api/users/:id.json';
  defaultParams = { id: '@id' }
  actions = {
    update: { method: 'PATCH' }
  }

  $resource(url, defaultParams, actions)

Users#$update()が生えているので,それ呼び出したらPATCHメソッドで送られる.
便利だ.

sample_app_controller.js.coffee
class UsersController

  # 省略

  submit: (user) ->
    user.$update()

それ以外のビジネスロジック

たとえばValidation?
ここでは簡単に,"name及びemailは空になってはならない"というものについて考える.

Railsで言うとこんなかんじ.

user.rb
class User
  include ActiveModel::Model

  attr_accessor :name, :email

  validate :name, presence: true
  validate :email, presence: true
end

実際の実装.
user.validate()で結果をboolで返すだけのもの.
(これぐらいだとビジネスロジックとは言わないか…)

user.js.coffee
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)のprototypeangular.extend()で拡張してメソッドをぶち込んでる.
かなしみ.

src/ngResource/resource.jsより抜粋
if (action.isArray) {
  value.length = 0;
  forEach(data, function(item) {
    if (typeof item === "object") {
      value.push(new Resource(item));
    } else {
      value.push(item);
    }
  });
}

参考文献

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25