In the "wire up a backend" demo code from the angularjs site they set up a db call. From what I can tell they're extending the update function in order to add some extra parameters needed by the mongolab api.
angular.module('mongolab', ['ngResource']).
factory('Project', function($resource) {
var Project = $resource('https://api.mongolab.com/api/1/databases' +
'/angularjs/collections/projects/:id',
{ apiKey: '4f847ad3e4b08a2eed5f3b54' }, {
update: { method: 'PUT' }
}
);
Project.prototype.update = function(cb) {
return Project.update({id: this._id.$oid},
angular.extend({}, this, {_id:undefined}), cb);
};
Then they call the update property like this:
$scope.save = function() {
$scope.project.update(function() {
$location.path('/');
});
I've tried using this code to build a demo app using a local development server so I've omitted extending the update property as I don't need the extra $oid parameter. What I do need is to specify that the update method should use PUT. My code is like this:
var Unit = $resource('http:/localhost/api/unit/:id', {id:'@Unit_Id'},
{'update': { method: 'PUT' }});
And then calling it like this:
$scope.save = function () {
$scope.unit.update(function () {
$location.path('/unitlist');
});
But What I've discovered is that the code only runs with a dollar sign in front of update like this:
$scope.save = function () {
$scope.unit.$update(function () {
$location.path('/unitlist');
});
So here are my questions:
"In the demo code, where is "update" actually added to the Project variable? As a parameter in $resource or using prototype to extend Project?"
Adding the following code to end of the factory() method:
console.log('Project.update=' + Project.update)
console.log('Project.prototype.update=' + Project.prototype.update)
return Project;
we see that Project.update is a function, and that Project.prototype.update is another/different function. So there are actually two update functions. Function Project.update is a (non-GET) "class" action, so it is called without a $ prefix. update() is a function defined on the object returned by $resource -- i.e., Project. Indeed, we see that function Project.prototype.update calls Project.update(...).
In the EditCtrl, when data is returned from the server, the project variable is a resource "instance" object (which is different from the resource "class" object), hence it has (non-GET) "instance" actions, which are prefixed with $. One of those actions is $update. Add the following log() to the EditCtrl function to prove that project.$update() exists:
Project.get({id: $routeParams.projectId}, function(project) {
console.log('project.$update=' + project.$update)
So now we have a third "update" function. However, in the demo code, they don't use this project.$update() function -- they use the function they defined on Project.prototype instead.
"Why is update undefined in my code unless I prefix $ when I call it?"
In your code, Unit.update should be defined (this is a resource "class" action), and when your data is returned from the server, then $scope.unit.$update becomes defined (this is a resource "instance" action). Unit is a class, $scope.unit is an instance.
In your code, you probably don't need to use Unit.update because I'm guessing you first Unit.get() your data, and then you assign the returned data to $scope.unit, and then you update it using the instance (not the class), hence you are updating with $scope.unit.$update() and not Unit.update(), which is the recommended approach.
Ok, here it is from the docs
The action methods on the class object or instance object can be invoked with the following parameters: 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])
So, when you when you extend the class (prototype), call it without the $ like normal, but when you add an action as a parameter of $resource prefix $.
As far as I get it they extend the prototype with this piece of code:
Project.prototype.update = function(cb) {
return Project.update({id: this._id.$oid}, angular.extend({}, this, {_id:undefined}), cb);
};
Then they create an instance of the Project in line 30 of the project.js
$scope.project = new Project(self.original);
And then they can perform an update by simply calling:
$scope.project.update(...)
If you got rid of extending the prototype of your service, you can't call $scope.unit.update because there exist no property of unit that is called update.
I hope it helps :)