7

I have an AngularJS $resource defined like this:

var Menus = $resource('http://cafe.com/api/menus');

and a RESTful API. So when I do a GET on Menus I get this back:

<cafe>
  <collection href="http://cafe.com/api/menus" type="menus">
    <template>
      <data name="Name" prompt="Menu name" />
    </template>
    <items>
      <item href="http://cafe.com/api/menus/1">
        <link href="http://cafe.com/api/menus/1/ingredients" rel="ingredients" />
        <data name="Name" prompt="Menu name">Morning</data>
      </item>
      <item href="http://cafe.com/api/menus/2">
        <link href="http://cafe.com/api/menus/2/ingredients" rel="ingredients" />
        <data name="Name" prompt="Menu name">Happy Hour</data>
      </item>
    </items>
  </collection>
</cafe>

Question is, how do I delete menu 2? (given that it has its own hypermedia link: http://cafe.com/api/menus/2)

Greg
  • 31,180
  • 18
  • 65
  • 85
  • Where are you stuck? Are you able to get the XML document into a JavaScript data structure, and you just aren't sure how to modify it? Are you not able to get the data structure created? What code do you have so far, and what are the results? – Michelle Tilley Nov 16 '12 at 09:20
  • I'd rather not start manipulating the JS object to extract the ID. I don't want IDs floating around my code. I'd rather use the self referencing item `href` to send a `DELETE` request to. I support I'm wondering whether each item is a type of `resource` object? or is that asking too much from Angular? – Greg Nov 16 '12 at 11:48
  • Ah, when you say "delete," you mean delete the resource on the server via HTTP. As far as I am aware, Angular doesn't understand XML--what is `Menus` (say, via `console.log`) once the promise is resolved in your app? – Michelle Tilley Nov 16 '12 at 17:24
  • I don't think AngularJS understands XML, so I would assume the whole XML document is contained as a string in a single $resource object. So you'd have to do some transformations to turn it into a useful JS object. Actually, I have found that using the $http service directly is easier than $resource, as I find $resource to be much too high-level and nowhere near flexible enough in regards to error handling (though, admittedly, I'm fairly new to AngularJS, so I might be missing something). – Joe Dyndale Nov 16 '12 at 22:05
  • It's JSON in reality, I'm using XML just for legibility. And yes using the HTTP Delete verb to delete "menu 2" from the collection. – Greg Nov 18 '12 at 18:01
  • @Greg - I don't know what your JSON actually looks like, but it seems fairly close to Collection+JSON. If you haven't looked at it, you might want to do that. It supports templates, lists of items which are lists of keys+values and links on collections and items. Read more here: http://amundsen.com/media-types/collection/ – Trygve Laugstøl Nov 22 '12 at 22:46
  • 1
    JSON is more readable to my chocolate salty eyeballs – aycanadal Feb 18 '15 at 10:06

2 Answers2

11

Assuming that you have gone from the XML to an Angular-managed array of JavaScript objects, you can use this to render your objects:

<tr ng-repeat="cafe in cafes">
    <td>{{cafe.name}}</td>
    <td>
        <button class="btn" ng-click="deleteCafe($index, cafe)">Delete</button>
    </td>
</tr>

and in your controller you can do this:

function ListCtrl($scope, $http, CafeService) {
  CafeService.list(function (cafes) {
    $scope.cafes = cafes;
  });

  $scope.deleteCafe = function (index, cafe) {
    $http.delete(cafe.self).then(function () {
      $scope.cafes.splice(index, 1);
    }, function () {
      // handle error here
    });
  }
}

Look, no client-side creation of URLs! :)

update: fixed a bug in the splice command, was splice(index, index), but should be splice(index, 1).

Trygve Laugstøl
  • 7,440
  • 2
  • 36
  • 40
  • it seems that when you get an array via a resource, like `var Menus = $resource('http://cafe.com/api/menus');` that doesn't mean each item in the array is a resource. Hence $http is the way to go in this instance... – Greg Nov 23 '12 at 17:56
  • 1
    @Greg - No, just set isArray:true like the documentation show you on GET already: http://docs.angularjs.org/api/ngResource.$resource – Trygve Laugstøl Apr 09 '13 at 21:17
  • Yep, agreed, didn't see that at the time. – Greg Apr 10 '13 at 10:03
2

If your REST service returns JSON to angular and the JSON include the menu ID in the returned data.

var Menu = $resource('http://cafe.com/api/menus/:id', { id: '@id' }); // replace @id with @<the id field in your json object>

// Delete menu 2
Menu.delete({id: 2}, function(){ // Success callback
  // Get all menus, 
  var menus = Menu.query(function() { // Success callback
    // alternative delete syntax:
    var lastMenu = menus.pop();
    lastMenu.$delete();
  });
});
Guillaume86
  • 14,341
  • 4
  • 53
  • 53
  • I don't want to pass the IDs around if I can help it. The resource belongs at the given HREF. So all I want to do is send a HTTP DELETE request to the given URL. Maybe I should loop through the menus and instantiate a custom menu object and assign the HREF to a property on the object.... – Greg Nov 20 '12 at 11:43
  • you can just use the regular $http service to make a DELETE request on the href if you don't want to use the $resource system – Guillaume86 Nov 20 '12 at 11:55
  • 1
    True but I'd like to know if I could treat each "Menu" in the Menus array like a resource object. So var menus = Menu.query(); Then menus[0].$delete(); is that possible? – Greg Nov 20 '12 at 12:22
  • 1
    yes it's what I did with the lastMenu in the demo (menus.pop() returns and remove the last item of the array) – Guillaume86 Nov 20 '12 at 12:39
  • 1
    @Greg - does this really solve your problem? Wasn't the whole point that you don't want to rely on the client-side generated URLs? It seems like a complicated way of doing 'Menu[2].$delete();' from what I can tell. – Trygve Laugstøl Nov 22 '12 at 10:47
  • I don't see what's complicated here, if you want to use your server generated urls use $http, $ressource is not meant for that ($ressource allows full client side scenarios, create client side, delete client side without getting all urls, just the inserted ID) – Guillaume86 Nov 22 '12 at 11:46
  • It's not complicated in itself. But your answer does not answer what @Greg wanted as you're not using the link the server generated. The example in the question isn't the best as the URLs are uniform and just happen to mesh well with the $resource service. – Trygve Laugstøl Nov 22 '12 at 12:35
  • Well IMHO API urls are designed to be easily templated so it's not a problem for me – Guillaume86 Nov 22 '12 at 14:25
  • @Guillaume86 The whole *point* of hypermedia and links is to not have this kind of out of bound information. Your answer is plainly wrong and misleading those who seek a way to use AngularJS against hypermedia-based APIs. – Trygve Laugstøl Nov 22 '12 at 20:07
  • feel free to downvote, as I said several times $ressource is not meant for hypermedia, you can write your own $hypermedia service by hacking the $ressource code if you want the $ressource style, the angular source code is well commented it should be a good exercise to get the internals – Guillaume86 Nov 22 '12 at 21:41
  • it seems that when you get an array via a resource, like `var Menus = $resource('http://cafe.com/api/menus');` that doesn't mean each item in the array is a resource. Hence $http is the way to go in this instance...would be nice to have resources acting a little smarter. Maybe a good idea for a new hypermedia module... – Greg Nov 23 '12 at 17:58