AngularJS Restangular and get a single url - angularjs

I have these "methods" in my angular service that use restangular to get remote data where the respose is this:
{
"1105":{"title":"","field_nazione":{"und":[{"value":null,"format":null,"safe_value":""}]},"field_redazionale":{"und":[{"value":null}]}},
"1110":{"title":"","field_nazione":{"und":[{"value":null,"format":null,"safe_value":""}]},"field_redazionale":{"und":[{"value":null}]}}
};
function restfulService(ipCookie,Restangular) {
return {
//Setta la directory di partenza del service rest. In questo modo non devo sempre definirlo
restfulBase : function() {
return Restangular.oneUrl('rest','http://MYREMOTEHOST/rest');
},
getAllCity : function () {
return this.restfulBase().get('cities', {'all':1}, {}, {'X-CSRF-Token': tokenVar});
},
....
};
Why when I call getAllCity() the url is :
http://MYDOMAIN/rest?0=c&1=i&2=t&3=i&4=e&5=s
?
If I use this :
Restangular.oneUrl('rest','http://MYDOMAIN/rest/cities').get({all : 1});
I have no problems.
I have tried changing my app to set Restangular.setBaseUrl() in .config() method and then changing my service to use Restangular.all('cities').get() but I have an error about "strings".
If I use getAll() I have an error about "getLists() want array and not objects".
So: which is the correct way to use Restangular ? I have read online documentation and tutorial, but I have not understand how to retrieve elements in the right way. And to "post".
Thanks and sorry for this stupid question.

I believe the problem is that you set your base as "one" type of resource. The "one" method is not for setting the base urls. The way I set the base url is like this:
angular.module('app')
.config(['RestangularProvider', function (RestangularProvider) {
// Set the base URL
RestangularProvider.setBaseUrl('http://MYREMOTEHOST/rest');
}]);
And then I access each resource, depending on its type with "one" or "all", like so:
function restfulService(ipCookie,Restangular) {
return {
getAllCity : function () {
return Restangular.all('cities').getList();
},
....
};
You can also set the default params in the config phase, or per request at runtime.
The "getLists() want array and not objects" error you get when you use "all" is because it accepts only arrays as a response, therefore you need to intercept the data before and parse it in an array. In your case, you are getting an object, so you can parse it like this:
// this happens at runtime, either in your implementation code or in a more global config file, like:
Restangular.addResponseInterceptor(function (data, operation, what, url, response, deferred) {
// If the what is set, than just grab it and return it
if (data.hasOwnProperty(what)) {
return data[what];
} else {
// Otherwise make it an array
var arr = [];
for (var key in data) {
arr.push(data[key]);
}
return arr;
});
Hope this helps.

Related

Required String parameter 'licenceplate' is not present"

I checked in different existing questions that was asked for similar problem but I didn't get any help for my problem.
In fact I can't use #RequestBody like in this question or this one.
I'm trying to pas some parameters from Angular controller to a Spring MVC controller, but I'm getting this error message
errorCode:500
message:"Required String parameter 'licenceplate' is not present"
here is my Angular Service:
myApp.httpEnterVehicle = function(levelNumber, placeNumber, licenceplate, placeType) {
return $http.put("/myApp/rest/vehicle/entervehicle", {
params : {
'licenceplate' : licenceplate,
'placeType' : placeType,
'placeNumber' : placeNumber,
'levelNumber' : levelNumber
},
});
};
and nothing was detected on my backend side wich seems to be strange
#RequestMapping(value = "/entervehicle", method = RequestMethod.PUT)
public ResponseEntity<Void> enterNewVehicle(#RequestParam("licenceplate") String licenceplate, #RequestParam("placeType") String placeType, #RequestParam("levelNumber") int levelNumber, #RequestParam("placeNumber") int placeNumber){
....
}
do you have any idea what's going on? I already tried toc check the content of my Angular service param and they are correct :(
You have incorrect put request call, it should look like below
$http.put('url', //1st parameter
{}, //request body
{} //request configuration here
);
If you compare you current put call you can see what wrong thing you were doing. You just need to pass {}(empty object) in request body the pass your config object in place of request body
myApp.httpEnterVehicle = function(levelNumber, placeNumber, licenceplate, placeType) {
return $http.put("/myApp/rest/vehicle/entervehicle",
{}, //added blank object as request body
{
params : {
'licenceplate' : licenceplate,
'placeType' : placeType,
'placeNumber' : placeNumber,
'levelNumber' : levelNumber
},
});
};

How to design angular service class for REST service with optional query params

I have a REST service which returns all the students.
URL : rest/students
I can add optional parameters to it like,
URL : rest/students?department=1001&valid=true
For this use case I have created an angular service,
angular.module('app.student').
factory('StudentService',StudentService);
StudentService.$inject = ['$http','ENV_CONSTANTS'];
function StudentService($http,ENV_CONSTANTS){
var service = {
getAllStudents : getAllSTudents,
getValidStudents : getValidStudents,
getValidStudentByDepartment : getValidStudentByDepartment
};
return service;
function getAllStudents(){
return $http.get(ENV_CONSTANTS.baseUrl+'/students');
}
function getValidStudents(){
return $http.get(ENV_CONSTANTS.baseUrl+'/students?valid=true');
}
function getValidStudentByDepartment (departmentId){
return $http.get(ENV_CONSTANTS.baseUrl+
'/students?valid=true&departmentId'+departmentId);
}
}
But I feel that it's not a good design, because for every query param or the combination of query param I need to create a method. Could anybody suggest a proper way to do this?
The url building ( baseUrl + "/my-suffix" ) is not of bad design imho.
The query parameter building is. $http.get can take a map for this :
$http.get(myUrl, { params : myParamMap })
I.E :
$http.get(myUrl, { params : { valid : true, departmentId : "myDepId" } });
This allow parameter building to be easier and prettier
You could also pre-generates your url constants :
var STUDENT_URL = ENV_CONSTANTS.baseUrl+'/students';
to avoid the url building in each of your methods
$http.get(STUDENT_URL, { params : myParams });
Which would be way more maintainable
Then you could factorize :
function performStudentCall(paramMap) {
return $http.get(STUDENT_URL, { params : paramMap });
}
to be able to call :
function getValidStudentByDepartment (departmentId) {
return performStudentCall({ valid : true, departmentId : departmentId });
}
here you would have one service method per action, which is the correct approach, while keeping only one method to performs all http calls.
You can create a function and pass the query param object with field value pair in function parameter.
something like
function getStudents(queryParamObject){
return $http.get(ENV_CONSTANTS.baseUrl+'/students', { params : queryParamObject });
}

Doing a GET passing a complex object with angular

I am using AngularJs and Resources module. I want to do a GET to obtain an object.. to do this GET I do not have to pass simply the ID to the server, but I should pass a complex object with different properties and values..
Here the code I am using:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
$scope.activationStatus =
new SeguiAttivazioneService
.seguiAttivazione()
.$get(
{
request: $scope.activationStatus
}, function () { });
}
};
On server side I have:
[HttpGet]
public IHttpActionResult GetActivationStatus(MyComplexObject request)
{
//I will do something here later...
return Ok();
}
The problem is that "request" arrive on server equals to NULL...
I have solved the problem passing two strings to the server... in this way:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
$scope.activationStatus =
new SeguiAttivazioneService
.seguiAttivazione()
.$get(
{
codiceFiscale: $scope.activationStatus.CodiceFiscale,
codiceRichiesta: $scope.activationStatus.CodiceRichiesta
}, function () { });
}
};
And server side:
[HttpGet]
public IHttpActionResult GetActivationStatus(string codiceFiscale, string codiceRichiesta)
{
return Ok();
}
In this way everything works... but I don't like this solution because I will have more than two input...
And this is a get, not a post (not a save, an update)...
How can I pass a complex object doing a GET?
Thank you...
It's best to use the POST method if you want to send data in the body of the request. While it's possible with Angular, some servers might ignore the body of GET requests.
This approach allows to send complex objects with arrays and sub objects:
Angular:
$http({
url: '/myApiUrl',
method: 'GET',
params: { param1: angular.toJson(myComplexObject, false) }
})
C#:
[HttpGet]
public string Get(string param1)
{
Type1 obj = new JavaScriptSerializer().Deserialize<Type1>(param1);
...
}
This is not an elegant solution but it works using HTTP GET:
$http.get(url + "?" + $.param(obj).replace(/%5b([^0-9].*?)%5d/gi, '.$1'))
It converts the complex object into a string with dot notation to define levels. Most of the server side frameworks like ASP.NET Core can bind it to complex objects.
This is an example of the string I send for a complex object:
StartDate=2021-06-11&EndDate=2021-06-11&TimeRange.TimeFrom.Time=07%3A00&TimeRange.TimeFrom.TimeFrame=AM&TimeRange.TimeTo.Time=10%3A00&TimeRange.TimeTo.TimeFrame=AM
Request body can only be sent by POST. With get you could at best URL Encode the OBJECT and then send it as query string params. But thats not the best solution to post some data to the server

How to make $resource accept array of strings (AngularJS)

I would like to make a request to a REST-service in which the query parameters contain an array of strings:
productRestService.getProductsInfo(productIdsArray,"id,name,rating").$promise.
then(function(productData) { // success: Produktdaten auslesen
updateProductList(productData);
}, function (error) {
console.log("Status: " + error.status);
});
The Resource-Service is as follows:
productRestService.getProductsInfo = function(productIds, properties) {
console.log('productRestService.getProductsInfo(): productIds' + productIds);
var productInfoResourceData;
var ProductInfoResource = $resource('/rest/products/productsInfo/:productIds/:properties',
{
productIds:'#productIds',
properties:'#properties'
}
);
productInfoResourceData = ProductInfoResource.query(
{
productIds: productIds,
properties: properties
}
);
return productInfoResourceData;
}
Calling the service results to an 404-Error, because the default behaviour of the $resource object is that it expects an array of an object when "query" is used.
How can I achieve that my $resoure-service will accept an array of strings? I tried to use "transformRequest" (see snippet below), but that did not work either.
{
query: {
method: 'GET',
isArray: true,
transformResponse: function (data, headers) {
var tranformed = [];
[].forEach.call(eval(data), function (d) {
tranformed.push({ name: d });
});
return tranformed;
}
}
}
A console.log within the function of the REST service productService.getProductsInfo shows the correct data that the service received:
["212999cc-063b-4ae8-99b5-61a0af39040d","17e42a28-b945-4d5f-bab1-719b3a897fd0","9307df3e-6e7a-4bed-9fec-a9d925ea7dc0"]
The URL is correct with the other REST-URLS and should look this way (and is being concatenated to the domain accordingly):
'/rest/products/productsInfo/:productIds/:properties'
EDIT:
The other functions within the productService responds in order, they do not use arrays but JSON objects and do not show unexpected behaviour.
(This was originally a comment, but it needed cleanly formatted code samples.)
I suspect your :productIds template parameter is getting filled into the template as "[object Object]". I've only seen your template URL, not the actual constructed URL, so I can't be sure.
If your server is expecting a URL where the :productsIds template parameter is JSON, like for example ---
rest/products/productsInfo/["id1","id2","id3"]/{"prop1":true,"prop2":false}
--- then try editing your getProductsInfo definition to something like this:
productRestService.getProductsInfo = function (productIds, properties) {
var ProductsInfo = $resource('/rest/products/productsInfo/:productIds/:properties', {
productIds: function () {
return angular.toJson(productIds);
},
properties: function () {
return angular.toJson(properties);
}
});
return ProductsInfo.query();
}
(Fair warning, I didn't test this code. It's just a quick edit of your example.)
This way, you're making sure that the parameter values are converting to the JSON that the server expects (if the server is expecting JSON in the URL, that is).

How can I synchronize two $resource calls in AngularJS

I am trying to do something like the following:
In my controller I have functions that use $recource call to get data from database. The service 'myService'
var fillSubData = function (containerToFill) {
resService.getSubDataFromDB(//$resource service
{params},
function (res) {
//do something with containerToFill with the result res add new values
}
);
}
var fillData = function (containerToFill) {
resService.getDataFromDB(//$resource service
{params},
function (res) {
//do something with containerToFill with the result res
fillSubData(containerToFill);
}
);
}
Controller
$scope.dataToFill;// object
var initialize = function () {
//by reference
myService.fillData(dataToFill);
// I need the dataToFill filled to do other thing with data recovered and built
angular.forEach(dataToFill.someArrayBuilt, function (item) {
//do something with item...
})
}
I need the dataToFill filled to do other thing with data recovered and built, but the resource calls are asyn, how can I do this?
Note that the resource actions return an object that contains a $promise property. You can use this to proceed with a callback once the async call has returned:
myService.fillData(dataToFill).$promise.then(function() {
// I need the dataToFill filled to do other thing with data recovered and built
angular.forEach(dataToFill.someArrayBuilt, function (item) {
//do something with item...
})
});
To enable this, I suggest that you simply have your fillData method return the result of the resource call:
var fillData = function (containerToFill) {
return resService.getDataFromDB(//$resource service ...

Resources