I have seen 100 examples of passing an ID into $resource.get() in order to query information out of a back-end in Angular. What I have not been able to find is how to pass a complex object.
If I have a table of objects to return, and I wish to run a search against them using multiple items of filter, I need to pass those items as parameters or as one complex parameter. For example, say I have a table of people's names and their cities, states, etc. I want to be able to say something like this:
var myResource = $resource(url);
myResource.get({name : "Mike", state : "Texas"});
The return may be a single row or multiple rows. But the point is how do I get the parameters off to the API call?
The way I have other methods set up that are simpler is by creating a repository in which I return like so:
return resource('/api/broker/productionInfo/');
Then in my API I do this (after the [RoutePrefix("api/broker")] setup:
[HttpGet]
[Route("productionInfo")]
public IHttpActionResult GetProductions()
{}
That's all awesome but I want to be able to add the search criteria in the repository call and then in the API method (i.e. extract from a querystring or however it is to be passed).
If I understand what you are asking correctly, you just want to pass additional parameters into an angular resource get request. It is as simple as what you have already suggested:
resource.get({id: 1, custom_param_1: "param1", custom_param_2: "param2"});
This would result in an http request that looks like this:
/resource/1?custom_param_1=param1&custom_param_2=param2
You can then extract these parameters on the API side of things.
Something to note is that get requests have a maximum length, and if you are attaching lots of different parameters to the request, it may be better to use a post or put instead.
The only thing I'm seeing that you're missing is a [FromUri] decorate attribute, in your GetProduction API method. Since Get supports only params binding through a query string (no body binding).
Your params:
options: {
StartDate: _startDate
EndDate: _endDate
TextSearch: "some search query....",
Page: 1,
PageSize: 25,
et...
}
Then, calling your repository from your controller:
repository.get(options).$promise.then(function (data) {
// data = response payload from backend
});
reposiroty
....
return resource('/api/broker/productionInfo/');
....
API
[HttpGet]
[Route("productionInfo")]
public IHttpActionResult GetProductions([FromUri] SearchCriteriaModel criteria) {
....
}
Hope that helps.
Related
I have an API like example
I have used cakephp HTTP client to get data, below my attempted code
public index()
{
$http = new Client();
$response = $http->get('https://restcountries.eu/rest/v2/all');
// $json = $response->getJson(); //also tried usgin json
$countries = $this->paginate($response);
$this->set(compact('countries '));
}
I am trying to apply pagination with this country data then fetch it in view with pagination.
After tried above code , I have gotten below error
Argument 1 passed to Cake\Datasource\Paginator::extractData() must be an instance of Cake\Datasource\RepositoryInterface, instance of Cake\Http\Client\Response given, called in \myapp\vendor\cakephp\cakephp\src\Datasource\Paginator.php on line 176
How can I get my desire result ?
You have probably need to implement a class who extend RepositoryInterface.
class JsonSource implements Cake\Datasource\RepositoryInterface
{ ... }
public index() {
$http = new Client();
$response = $http->get('https://restcountries.eu/rest/v2/all');
$src = new JsonSource();
$src->fromResponse($response);
$countries = $this->paginate($src);
$this->set(compact('countries ')); }
Is a bit tedious, because you need to define Json like a datasource.
The default pagination only supports querying tables (repositories), or operating on pre-built query instances.
To extend on #Zeppi's answer. You basically have three somewhat straightforward options here:
Create custom query/repository implementations as hinted by #Zeppi.
This can indeed be quite a lot of work though, so you might want to look into alternatively implementing it with the help of plugins, for example muffin/webservice, which does most of the hard work of implementing the required interfaces.
Or create a custom paginator that actually accepts and works on array data.
Or use what is widely know as a "datatable", that is a JavaScript based table in the frontend that paginates the data, for example jQuery DataTables.
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?
I am trying to get to Web API GET controller using $http.get in angular application as follows :
$http.get(BasePath + '/api/documentapi/GetDocuments/' ,
{
params: {
PrimaryID: ID1,
AlternateID: ID2,
}
}).then( ...
In my case, either the PrimaryID or the AlternateID will have the value. So, one of them will be null always.
My Web api method is
public DocumentsDto[] GetDocuments(decimal? PrimaryID, decimal? AlternateID)
{ ...
When one of the value is null, the url generated by $http.get is as follows :
http://BaseServerPath/api/documentapi/GetDocuments/?PrimaryID=1688
or
http://BaseServerPath/api/documentapi/GetDocuments/?AlternateID=154
This does not hit my Web API method.
However if I use
http://BaseServerPath/api/documentapi/GetDocuments/?PrimaryID=1688&AlternateID=null
it works. I can hardcode the values to null in my params, however I would like to know if there is any correct way to achieve this.
Thanks,
Sam
I got the correct answer from #RobJ. He has posted a link to the answer. I am pasting the same answer here as well. The solution is to have default values for the Web API parameters.
public string GetFindBooks(string author="", string title="", string isbn="", string somethingelse="", DateTime? date= null)
{
// ...
}
In my case it will be
public DocumentsDto[] GetDocuments(decimal? PrimaryID = null, decimal? AlternateID = null)
{ ...
Although you've specified on your Web API controller that the two parameters can be null, the ASP.NET routing engine will still be looking for two parameters in a call to that method - even if one of them is null.
Ideally, you'd create two methods, one which takes just the primary and one just the secondary but in your case this is slightly tricky as both your IDs are of the same type. Although you can specify which parameter corresponds to the supplied value in the query string, both these methods will have the same signature (a single parameter of type decimal) in your controller class.
So you have two options here. Either create new controller so you have one which receives queries for the PrimaryID and one for the SecondaryID, or you have one method which takes an object containing one ID set to a value and the other to null, and run your query based on that.
And yet another option can be to convert the request params to a complex object and use [FromUri] to create the object from Url.
you can try this:
$http.get(BasePath + '/api/documentapi/GetDocuments/' ,
{
params: {
PrimaryID: ID1!=undefined?ID1:0,
AlternateID: ID2!=undefined?ID2:0,
}
}).then( ...
then you can handle 0 in webapi...
I need to create a fairly complex query string in Restangular.
http://vdmta.rd.mycompany.net//people?anr=Smith&attrs=givenName,displayName,name,cn
How do I do this?
So far I am OK getting as far as ?anr=Smith using this:
return Restangular.all('/people').getList({anr:searchTerm});
The last part attrs=x,y,x lets me control which attributes I want back in the search and could change per request I make.
Any advice appreciated.
Regards
i
You should be able to simply add another query parameter where the value is your comma separated list of attributes.
var attributes = ['givenName' , 'displayName']; // attributes you require for the request
var attributesAsString = attributes.join();
return Restangular.all('/people').getList({
anr : searchTerm,
attrs: attributesAsString
});
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/