RESTful thông qua $resource của AngularJS

I. Mở đầu

1. $resource là gì?

  • $resrouce là một service nó không có sẵn trong thư viện của AngularJS. Bạn phải download nó và include vào trong ứng dụng.
        <script type="text/javascript" src="angular.js"></script>
        <script type="text/javascript" src="angular-resource.js"></script>

  • $resource là một factory nó tạo ra một resource object cho phép chúng tương tác với RESTful phía server.
  • The returned resource object has action methods which provide high-level behaviors without the need to interact with the low level $http service.
  • Resource object có đầy đủ các phương thức cho các hành vi khác nhau mà không cần phải tương tác với các service của $http (low level)

2. $http vs $resource

a. $http

$http service là một dịch vụ cốt lõi của Angular, được sử dụng để giao tiếp với các trình chủ HTTP thông qua các đối tượng XMLHttpRequest của trình duyệt.

$http service gần giống như phương thức $.ajax() trong jQuery. $http sẽ request và được trả về một promise. $http chỉ dùng cho việc gọi Ajax thông thường với các phương thức get, post, delete, put....

  • $http.get(url, [config])
  • $http.delete(url, [config])
  • $http.head(url, [config])
  • $http.patch(url, data, [config])
  • $http.post(url, data, [config])
  • $http.put(url, data, [config])
  • $http.jsonp(url, [config])

Chú ý rằng, phương thức $http.post(), $http.put() và $http.patch() có tham số data chứa dữ liệu được gửi đến server. Các phương thức còn lại không thể có tham số data.

Tham số data là một chuỗi JSON được đưa vào trong phần request body. AngularJS sẽ coi tất cả các thuộc tính bắt đầu với ký tự $ là của riêng nó, do đó nó sẽ loại bỏ $ ra khỏi data. Nếu dữ liệu của bạn cần chứa các thuộc tính bắt đầu với $ thì bạn cần chuyển đối tượng data thành chuỗi của riêng bạn bằng cách sử dụng hàm JSON.stringify(data)

b. $resource

$resource được xây dựng dựa trên $http

$resource giúp cho việc xây dựng một ứng dụng RESTful backend trở nên dễ dàng hơn, code ngắn gọn hơn

II. Cách thức hoạt động của $resource

1. Sử dụng $resource

  • AngularJS cung cấp dịch vụ $resource thông qua module ngResource
        angular.module('mainApp',['ngResource']);

  • Bạn có thể sử dụng $resource trong (service, controller ... )

2. Thành phần và hoạt động

  • $resource làm việc với RESTful backend theo quy tắc:
URL Http verb Body request
http://localhost:3000/api/v1/words GET Rỗng
http://localhost:3000/api/v1/words POST Json
http://localhost:3000/api/v1/words/:id GET Rỗng
http://localhost:3000/api/v1/words/:id PUT JSON
http://localhost:3000/api/v1/words/:id DELETE Rỗng
        angular.module('mainApp').factory('Word', function($resource) {
          return $resource('/api/v1/words/:id');
        });

$resource sẽ trả về một resource class với 5 phương thức mặc định: get(), save(), query(), remove(), delete()

ví dụ

angular.module('myApp.controllers',[]);

angular.module('myApp.controllers').controller('ResourceController',function($scope, Word) {
  var word = Word.get({ id: $scope.id }, function() {
    // something
  }); // get() trả về một word

  var words = Word.query(function() {
    // something
  }); //query() trả về một mảng words

  $scope.word = new Word(); Một resource instance

  $scope.word.content = 'New word';

  Entry.save($scope.entry, function() {
    //do something
  });
});

Hàm get()

  • Hàm get() sẽ request với phương thức GET đến /api/v1/words/:id. Tham số id trên url sẽ được thay bởi $scope. Hàm get() sẽ trả về đối tượng rỗng và nó chỉ nó được tự động cập nhật khi có data từ phía server trả về.
  • Tham số thứ 2 trong hàm get() là một callback được gọi khi có data từ phía server trả về.

Hàm query()

  • Hàm này sẽ request với phương thức GET đến /api/v1/words và trả về một mảng rỗng. Và mảng này được update khi có data từ server trả về, cũng giống như kiểu trả về của hàm get(). Và callback của hàm query() sẽ được gọi mỗi khi có data từ phía server trả về.

Hàm save()

  • Hàm save() sẽ request một với phương thức POST đến /api/v1/words. Tham số đầu là data body, tham số thứ 2 là một callback được gọi khi data được lưu.
  • Ta có thể gọi lại một resource class, thiết lập các thuộc tính cho nó và lưu trữ đối tượng vào phía server

3. Các action method của Resource Class và Resource Instance

  • HTTP GET "class" actions: Resource.action([parameters], [success], [error])

  • non-GET "class" actions: Resource.action([parameters], postData, [success], [error])

  • non-GET instance actions: instance.$action([parameters], [success], [error])

Class action gọi phương thức sẽ không có tiền tố $, đối với instance action thì ngược lại.

    Word= $resource('/api/v1/words/:id, {id:'@id'});
    word = Word.get(id: 11)
    Word.save(word)  tương đương với word.$save()

Word gọi là resource refactor. $resource gọi là resource constructor.

  • Success callback được gọi với các tham số (value, responseHeaders), value là resource instance hoặc các collection object.
  • Error callback được gọi với một tham số (httpResponse)
  • Class action trả về các empty instance, trong khi đó instance action trả về promise của action

Các Resource instance và collection có các thuộc tính:

$promise: việc thực hiện các request thông qua web service thường trả lại dữ liệu với độ trễ nhất định. Để đảm bảo dữ liệu đã sẵn sàng trước khi gán nó vào model hoặc render lên view, chúng ta có thể sử dụng promise. $resolved: mặc định là false, sau khi tương tác với server lần đầu tiên hoàn thành (dù success hay fail) nó được thiết lập giá trị true.

III. Ứng dụng

controllers/words_controller.js

angular.module('wordApp.controllers', []).controller('WordListController', function($scope, $state, popupService, $window, Word) {
  $scope.words = Word.query();

  $scope.deleteWord = function(word) {
    if (popupService.showPopup('Really delete this?')) {
      word.$delete(function() {
        $window.location.href = ''; //redirect to home
      });
    }
  };
}).controller('WordShowController', function($scope, $stateParams, Word) {
  $scope.word = Word.get({ id: $stateParams.id });
}).controller('WordCreateController', function($scope, $state, $stateParams, Word) {
  $scope.word = new Word();

  $scope.addWord = function() {
    $scope.word.$save(function() {
      $state.go('words');
    });
  };
}).controller('WordEditController', function($scope, $state, $stateParams, Word) {
  $scope.updateWord = function() {
    $scope.word.$update(function() {
      $state.go('words');
    });
  };

  $scope.loadWord = function() {
    $scope.word = Word.get({ id: $stateParams.id });
  };

  $scope.loadWord();
});

words/app.js

Chú ý routes sử dụng Angular UI Routes bạn có thể tham khảo cách cài đặt và dùng ở đây https://github.com/angular-ui/ui-router


angular.module('wordApp', ['ui.router', 'ngResource', 'wordApp.controllers', 'wordApp.services']);

angular.module('wordApp').config(function($stateProvider) {
  $stateProvider.state('words', {
    url: '/api/v1/words',
    templateUrl: '/templates/words.html',
    controller: 'WordListController'
  }).state('showWord', {
    url: '/api/v1/words/:id/view',
    templateUrl: '/templates/show.html',
    controller: 'WordShowController'
  }).state('newWord', {
    url: '/api/v1/words/new',
    templateUrl: '/templates/add.html',
    controller: 'WordCreateController'
  }).state('editWord', {
    url: '/api/words/:id/edit',
    templateUrl: '/templates/edit.html',
    controller: 'WordEditController'
  });
}).run(function($state) {
  $state.go('words');
});

Mỗi một state sẽ bao gồm url, template và controller. Như trên thì newWord là một state đi đến trang new

services.js

angular.module('wordApp.services', []).factory('Word', function($resource) {
  return $resource('http://localhost:3000/api/v1/words/:id', { id: '@_id' }, {
    update: {
      method: 'PUT'
    }
  });
});

Tham khảo ứng dụng tại đây AngularJS

IV. Nguồn tham khảo

http://www.sitepoint.com/

https://www.omniref.com

http://angularjs.org