AngularJS - PUT method not working (404 error)

Problem

I'm new to AngularJS and I have trouble to update an object via REST. I'm using a PHP/Mysql Backend (Slim Framework).
I'm able to retrieve (GET), create (POST) a new object but not to edit (PUT) one. Here's the code:

my Form:

<form name="actionForm" novalidate ng-submit="submitAction();">
  Name: <input type="text" ng-model="action.name" name="name" required>
  <input type="submit">
</form>

My service:

var AppServices = angular.module('AppServices', ['ngResource'])
AppServices.factory('appFactory', function($resource) {
  return $resource('/api/main/actions/:actionid', {}, {
    'update': { method: 'PUT'},
  });
});

app.js

var app = angular.module('app', ['AppServices'])
app.config(function($routeProvider) {
  $routeProvider.when('/main/actions', {
    templateUrl: 'partials/main.html',
    controller: 'ActionListCtrl'
  });
  $routeProvider.when('/main/actions/:actionid', {
    templateUrl: 'partials/main.html',
    controller: 'ActionDetailCtrl'
  });
  $routeProvider.otherwise({redirectTo: '/main/actions'});
});

controllers.js:

function ActionDetailCtrl($scope, $routeParams, appFactory, $location) {
  $scope.action = appFactory.get({actionid: $routeParams.actionid});
  $scope.addAction = function() {
    $location.path("/main/actions/new");
  }
  $scope.submitAction = function() {
    // UPDATE CASE
    if ($scope.action.actionid > 0) {
      $scope.action = appFactory.update($scope.action);
      alert('Action "' + $scope.action.title + '" updated');
    } else {
      // CREATE CASE
      $scope.action = appFactory.save($scope.action);
      alert('Action "' + $scope.action.title + '" created');
    }
    $location.path("/main/actions");
  }
}

In Slim, in api/index.php, I've got these routes and functions defined:

$app->get('/main/actions', 'getActions');
$app->get('/main/actions/:actionid',    'getAction');
$app->post('/main/actions', 'addAction');
$app->put('/main/actions/:actionid', 'updateAction');

When I create a new "action", everything is working as expected. But when I try to edit an existing one, I've got this error:

PUT http://project.local/api/main/actions 404 Not Found

The action is not updated (although the alert message "Action xxx updated" is displayed)

Is it an issue with my routeProvider setting ? I guess the PUT url misses the id at the end...

I precise that if I try to simulate the PUT request with POSTMan-Chrome-Extension for example, everything is working well (PUT http://project.local/api/main/actions/3 returns the expected data)

Problem courtesy of: bsfoo116

Solution

After reading more carefully, the problem is indeed that you don't send the id in the url when you do the update request. Furthermore, the way you call update / save is not quite what is intended with resource. After you have created a resource, you call the save / update methods on the instance, not as a factory function. You can also bind properties of the instance to the params in the url, so you don't have to specify them on each call:

AppServices.factory('appFactory', function($resource) {
  return $resource('/api/main/actions/:actionid', {actionid : '@actionid'}, {
    'update': { method: 'PUT'},
});

The second parameter of resource tells angular which properties it should use to populate the url parameters. so the get operation stays the same:

$scope.action = appFactory.get({actionid: $routeParams.actionid});

and the update is now:

$scope.submitAction = function() {
  // UPDATE CASE
  if ($scope.action.actionid > 0) {
    $scope.action.$update()
  } else {
    $scope.action.$save();  
  }
}

Since you used angular-cellar as a basis, I should probably check and see if I can improve this ...

Solution courtesy of: Narretz

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.