here's the relevant snippet of code:
$scope.submit = function() {
console.log(this);
weekly_habits = $resource('/api/users/:user_id/weekly_habits/:id/', {user_id: '#user'});
entry = weekly_habits.save({name: $scope.newAccomp, count: 0});
$scope.accomplishments.unshift(entry);
$scope.newAccomp = '';
}
my error is that no route matches /api/users/weekly_habits... My project is built in rails and I don't understand what this line means {user_id: '#user'}. Where is this #user object supposed to be? It would be much appreciated if someone explained what's going on here.
Thanks!
From the documentation:
If the parameter value is prefixed with # then the value of that parameter is extracted from the data object (useful for non-GET operations).
And later on they have an example
var User = $resource('/user/:userId', {userId:'#id'});
So the second argument to the resource service are the default parameters. In this case, by default, the userId will be extracted from the resource object you call a method on.
Previously I had an example of a GET operation, which doesn't really make sense in this case. But imagine you were doing a POST ($save) request with a data object. Angular would automatically extract the userId from the data object and inject it into the URL for you. You don't have to manually specify the value for the URL.
More info can be found on the doc page.
http://docs.angularjs.org/api/ngResource.$resource
Quoting the documentation: "If the parameter value is prefixed with # then the value of that parameter is extracted from the data object (useful for non-GET operations)."
The '#user' tells Angular to extract the value of user_id from the 'user' property of the object. So if you call .save() on an object that has an 'user' property of 'abc123', then the :user_id in your URL will be replaced with 'abc123'.
Related
I have an array of id let's say
favorites = [102,110,112,125]
I want to retrieve the corresponding object for each id by passing it to query string like this :
public getFavorites(favs){
let favorites = favs.join();
let encodedUrl = encodeURIComponent(JSON.stringify({"id": favorites }));
return this.http.get(this.api_url + '/1/query/data/getFavs?parameters='+encodedUrl, {
headers: this.authHeader
})
.retry(3)
.map(res => res.json());
}
The problem is only one object appear in my html template and also in the console. What is the best way for me to pass an array of value to a URL as parameters in order to retrieve the associated objects?
You can pass multiple parameter values with the same name over the querystring. Does that help you? For example, here's a snippet:
this.api_url + '/1/query/data/getFavs?id=101&id=110
Here is another answer that has some more info on this.
If you have to send the ID's over in a serialized manner, consider posting the JSON instead of using the GET method. If you're trying to maintain adherence to REST verb standards by making it a get call, can you post the server code?
The Problem:
I have code to set up a $resource that seems to compile without error:
var ReportsRest = $resource('/reports/:reportId', {reportId: '#id'});
ReportsRest.get({id: 123});
but when that code actually executes the request url that is generated looks like this:
GET http://localhost:5523/reports?id=123 404 (Not Found)
The id is not being parsed and dynamically loaded into the URI. Is there something that I am missing?
Plunkr
http://plnkr.co/edit/3ikqMsnDI9r9LThaQLf3?p=preview
Try this:
var ReportsRest = $resource('/reports/:reportId', {reportId: '#id'});
ReportsRest.get({reportId: 123});
Under $resource Usage, there is this block of text.
paramDefaults
Default values for url parameters. These can be overridden in actions methods. If any of the parameter value is a function, it will be executed every time when a param value needs to be obtained for a request (unless the param was overridden).
Each key value in the parameter object is first bound to url template if present and then any excess keys are appended to the url search query after the ?.
Given a template /path/:verb and parameter {verb:'greet', salutation:'Hello'} results in URL /path/greet?salutation=Hello.
If the parameter value is prefixed with # then the value for that parameter will be extracted from the corresponding property on the data object (provided when calling an action method). For example, if the defaultParam object is {someParam: '#someProp'} then the value of someParam will be data.someProp.
To summarize, the object you pass in needs to use the key of your paramDefaults object to get the value. That value replaces the same :key text in your URL pattern. Any value in the paramDefaults object that is prefixed with an # will be set on the returned model data as a property named whatever follows the #.
var ReportsRest = $resource('/reports/:reportId', {reportId: '#id'});
ReportsRest.get({
reportId: 123,
other: 123
}, function(data) { /* ... */ });
This makes a request to /reports/123?other=123. data, in the callback, looks like { id: 123 }.
I'm trying to post the scalar value 0 with angular resource, e.g.
myResource.save({}, 0, onSuccess, onError};
This gives a HTTP 400 error for a POST attempt with empty body.
Looking into the angular sources I see that my post data ultimately becomes the argument to the constructor of Resource, which looks like
function Resource(value){
shallowClearAndCopy(value || {}, this);
}
So it seems all falsy values will be replaced by an empty object and thus cannot be posted. Is this by design (and then: which part of the documentation did I miss?) or a bug?
The point of $resource is best illustrated when the instance methods are used instead of the class methods. Take this example from the docs:
var CreditCard = $resource('/user/:userId/card/:cardId',
{userId:123, cardId:'#id'}, {
charge: {method:'POST', params:{charge:true}}
});
...
var newCard = new CreditCard({number:'0123'});
newCard.name = "Mike Smith";
newCard.$save();
Essentially newCard is just a plain object representing a model, but enriched with some functionality. $resource provides a layer of abstraction. It's an implementation of the Active Record Pattern.
That said, if you want to post a single scalar value, then chances are that you are dealing with a service rather than a resource. In that case it's somewhat obvious that $resource (sic!) isn't the right choice.
from the documentation (http://docs.angularjs.org/api/ngResource.$resource):
$resource(url[, paramDefaults][, actions]);
paramDefaults(optional) – {Object=} – Default values for url parameters.
...
If the parameter value is prefixed with # then the value of that parameter is extracted from the data object.
The question is what data object do they refer to? How to use this feature?
lets say you have a resource like this:
var User = $resource('/user/:userId', {userId:'#id'});
var user = User.get({userId:123});
It means that the value of :userId in your url will be replaced with the id property from the user object when that property is required.
So when is it required? Its required when you are doing something to an existing user, like geting one, updating one. It is not required when you create a user.
In most cases, you will want to have at least one param prefixed with # in your REST url that resource uses (probably the object id). If you dont have one, that means that in order for you to save an instance of an object, you dont need to know anything about where its stored. This implies that its a singleton object. Maybe like a settings object.
Here is your long awaited example:
var User = $resource('/user/:userId/:dogName', {userId:'#id', dogName:#dog});
User.get({userId:123, dog:'Matt'}, function() { .. })
will produce the request: GET /user/123/Matt
I created my web site having 2 types of users: admin and user. So, I created 3 pages mainpag.html, admin.html, user.html. and separate models, views, collections, routers.js files for each of them. After logging in, as I am sending users to separate HTML pages with different models, I can't automatically get user model. so I did like this:
First, I made AJAX call to server, asking for the _id (username in session, so I can get id)
from the id, I fetched the model, by model.fetch(), then I got my usermodel with all attributes.
then in the success callback of fetch, I did model.save({weight: "somevalue"}). According to me, it should update right, as the model is already available, that attribute weight also available with some old value, but it is sending POST request, also when I tried model.isNew(), it returned true. Where am I wrong? how can I update my model? I will post more details if required.
More details:
If I remove that save method, then I am getting correct attributes in the model.
If I don't remove that save method, that success and error callbacks are also appearing as attributes in the model.
Code:
addWeight : (e)->
arr=new Array()
arr['_id']=app._id
console.log "asdasd"
console.log arr
console.log arr['_id']
#user_model =new UserModel(arr)
#user_model.fetch({
success : (model,res,options) =>
console.log model
console.log res
arr=new Array()
arr['_id']=e.target.id
#arr['action']='weight' #means , update weight
##user_model.setArr(arr)
##user_model.set({weight : arr['_id']})
console.log "new : "+#user_model.isNew()
#user_model.save({weight : e.target.id})
##user_model.save({
# success : (model,res,options) =>
# console.log "model updated: "+JSON.stringify(model)
# console.log "Res : "+JSON.stringify(res)
# error : (model,res,options) =>
# console.log "Error : "+JSON.stringify(res)
#})
error : (model,res,options) =>
console.log "Error "
})
the above code is written in coffeescript, so even if you don't know coffeescript, don't worry, you can understand easily, and those # mean, it is a comment. here we follow indentation instead of braces.
one more doubt, a model's URL must be changed dynamically according to the requirement, right? what is the best way to achieve that? I am doing like this:
I am populating "array" containing the required fields that should be present in the URL. In model, s init func, I am using #arr=arr, then in URLs function, I check like this.
url : ->
if #arr['id']
"/user/#{#id}"
Is my approach right, or any better approach is there for dynamically setting URLs. Or can I directly set the URLs like this:
#user_model.setUrl "/someurl/someid" //this setUrl method is available in model's definition
#user_model.fetch() or save() or watever that needs url
Just a hunch, but you mentioned that you call model.fetch() to retrieve the _id field. Be sure to either return an id field instead _id (notice the underscore).
The call to model.isNew() returning true is an indicator that the id property was never set from the model.fetch() call.
I look forward to a possible further explanation with your code...
Looking at your code:
/* The model needs an 'id' attribute in order to marked as not new */
#user_model = new UserModel(id: arr['_id'])
Actually if you call
model.set({weight: "somevalue"});
It will update the value in the model, but it won't send a POST request
model.save(attribute);
Actually calls Backbone.sync as you probably know.
EDIT :
You might want ot set
m = Backbone.Model.extend({
idAttribute: '_id'
});
to every model, because the isNew method actually checks if the model has id attribute
Regarding to this you could see here that .set doesn't call backbone.sync here : http://jsfiddle.net/5M9HH/1/