简体   繁体   中英

How to specify different URLs for collections vs. single records with ngResource

I am trying to use ngResource to consume a firebase rest API. This API uses slightly different URLs for retrieving collections vs individual records. For example, I have a collection that I access with:

https://angular-resource-test.firebaseIO.com/systems.json

But if I want to access an individual system I use:

https://angular-resource-test.firebaseIO.com/systems/1.json

How do I specify a parameter-based URL for this in the resource declaration?

Normally I would do something like

app.factory('System', ['$resource', function($resource) {
  var System = $resource(
    'https://angular-resource-test.firebaseIO.com/systems/:id.json',
    {id: "@id"},
    {update: {method: "PUT"}}
  );
  return System;
}]);

But that fails for the collection because it lacks the trailing .json. Alternatively, when I specify a URL that works for the collection, the case of selecting individual rows fails. See this jsfiddle for an example:

http://jsfiddle.net/D5E6w/15/

There are 2 methods that send an HTTP GET in a resource.

  • get : Expect to receive an object
  • query : Expect to receive an array

Your api isn't very restful and because of this, you will need 2 resources to do what you want since they use different URI (see Carl's answer). I dont know if you can edit your REST service, but the good way to do it would be : https://angular-resource-test.firebaseIO.com/systems/ for a query (expect an array) https://angular-resource-test.firebaseIO.com/systems/:id for a get. (expect an object)

With this service, you could use your resource :

var System = $resource(
  'https://angular-resource-test.firebaseIO.com/systems/:id',
  {id: "@id"},
  {update: {method: "PUT"}}
);

You would do your calls like this :

var systems = System.query({});
var system = System.get({id:1});

Your problem should be solved by using isArray: true for your query and get methods for System and SystemType. It has to do with how your json is formatted on the server-side. See angular docs for expanded discussion. http://jsfiddle.net/D5E6w/24/

{
   update: { method: "PUT" },
   query: { method: "GET", isArray: true },
   get: { method: "GET", isArray: true }
}

Here is a working example with both a collection of systems and a single record. Note the isArray value for each. http://jsfiddle.net/D5E6w/51/

here is my solution with replacing the entire $resource URL. I needed that because I am using HAL Rest response and when paginating for instance, I wanted to replace the entire URL and not only params in it.

app.factory('$rest', ['$resource', 'HALParser', function($resource, HALParser) {
    return function($url) {
        $url = ($url == null) ? 'http://localhost:8000/:type' : $url;
        return $resource($url, {type: ''}, {
            update: { method:'PUT' },
            get : {
                method: 'GET',
                transformResponse: [function(data) {
                    return (new HALParser()).parse(angular.fromJson(data));
                }]
            }
        });
    }
}]);

and then,

app.controller('VendorsController', ['$scope', '$rest', 
        function($scope, $rest) {

        $scope.data = $rest().get({type: 'vendors'});

        $scope.create = function() {
            $rest().save({type: 'vendors'}, {name: $scope.item});
        };
        $scope.load = function($item) {
            console.log($item);
        };

        $scope.page = function($url) {
            $scope.data = $rest($url).get();
        };
    }]);

I simply wrapped $resource return from my service info a function with an argument URL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM