Sending Array of Objects to Web API from AngualrJS - angularjs

During this process, I grab an array of "vehicles" from the Web API. I modify and do whatever to each vehicle. Then I want to send the list back, without going through and looping...
I've tried a lot of the ways that i've looked up.
I've got this in the WEB API for a breakpoint to see if I can even get the array there, but I havent been able to yet.
public IHttpActionResult UpdateVehicles(Vehicle[] vehiclesArry)
{
return Ok();
}
I'm confused if I need to do a $post, or if I could just "get" it to the correct method like I've been doing. The problem is I can't get the array to the WEB API method.
I've got my $resource setup like this.
return $resource(appSettings.serverPath + "/api/Violators/:id",null,
{
'update': { method: 'PUT' },
'delete': { method: 'DELETE' },
'post': { method: 'POST' }
});
I've tried using $post, but it says the object doesn't support it. I'm not sure what other ways I can try. I've tried using "dynamic" in the web API, that doesn't seem to work either.

You're missing the params object for $resource, so it doesn't know the id.
return $resource(appSettings.serverPath + "/api/Violators/:id", { id: '#id' });
You don't need to explicitly setup methods for get, post, delete. That's already done for you. If your API uses PUT for update, set that up like this:
return $resource(appSettings.serverPath + "/api/Violators/:id", { id: '#id' }, {
update: { method: 'PUT' }
});
Also, the property on your resource must be vehiclesArry exactly or web API won't know how to map it. I also want to echo #sowen. You will need to setup a view model that your endpoint receives.

My assumption is that you are having some script errors in your page or you are not using the $http methods properly.
One problem people usually run into is using the correct url to the web api endpoints in your angular controller. If you don't get it right, you might be getting 404 errors. Look for those in your browser console(network tab)
The below code should work fine without any issues
$http.get("../api/Values/")
.then(function (res) {
var vehicles = res.data;
console.log('data received', JSON.stringify(vehicles));
//Let's update the Name of each vehicle.
$.each(vehicles, function (indx, item) {
item.Name = item.Name + " Updated";
});
console.log('data modified', JSON.stringify(vehicles));
//Let's make a call to web api with modified data
$http.post("../api/Values/UpdateVehicles", vehicles)
.then(function (res2) {
console.log('response', JSON.stringify(res2.data));
});
});
Assuming you have angular js properly loaded in your page and the above code is part of your angular controller for the current page and you have the Web api controller with 2 action methods like below example.
public class ValuesController : ApiController
{
[HttpPost]
[Route("api/Values/UpdateVehicles")]
public IHttpActionResult UpdateVehicles(Vehicle[] vehiclesArry)
{
// just returning whatever came in for TESTING PURPOSE
return Ok(vehiclesArry);
}
public IEnumerable<Vehicle> Get()
{
return new List<Vehicle>
{
new Vehicle {Id = 1, Name = "Car"},
new Vehicle {Id = 2, Name = "Van"}
};
}
}
Also,FYI : I am using Attribute routing in my api controller for the UpdateVehicle endpoint.

Create a model object like
public class UpdateReq
{
public IEnumerable<Vehicle> Vehicles { get; set; }
}
From your angular, just pass a json with an array
{
[v1, v2, v3]
}

Related

handling an angular $http request in symfony controller

i want to send data from a twig view to a symfony controller using angular js $http method
this is my javascript
<script>
var app = angular.module('app',[]);
app.controller('ctrl',function($scope,$http) {
$scope.processForm = function() {
var val = $scope.libelle;
$http({
method: "POST",
url: 'http://localhost/symangular/web/app_dev.php/home',
headers: {
'Content-Type': 'application/json'
},
data:{libelle:val}
}).then(function (html) {
console.log(html);
});
}
});
</script>
and this is my controller
class DefaultController extends Controller
{
public function indexAction(Request $request)
{
$prod = new Product();
$form = $this->createForm(ProductType::class,$prod);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid() && $request- >isMethod('POST') && $request->isXmlHttpRequest()){
$em = $this->getDoctrine()->getManager();
$data = json_decode($request->getContent(), true);
dump($request->request->get('libelle'));
$request->request->replace($data);
$prod->setLibelle($request->request->get('libelle'));
$em->persist($prod);
$em->flush();
return new JsonResponse("good");
}
return $this->render('angulartestangularBundle:Default:index.html.twig',array('form'=>$form->createView()));
}
}
so when i execute i got an object in the console that i didn't understand it also i got nothing in database , did anyone have an idea about how to handle an
$http angular request in symfony controller
Object {data: "<script src="https://ajax.googleapis.com/ajax/libs…: 5 } ); })();/*]]>*/</script>↵</body>↵", status: 200, config: Object, statusText: "OK"}
In Symfony, a request considered as a XmlHttpRequest by reading request headers. The exactly code in Symfony is:
public function isXmlHttpRequest()
{
return 'XMLHttpRequest' == $this->headers->get('X-Requested-With');
}
So, when using angularjs or any javascript framework to make a XMLHttpRequest, you should add a header with X-Requested-With key and value = XMLHttpRequest. This header also required even if you're using fetch api. In your code abow, the request call should be:
$http({
method: "POST",
url: 'http://localhost/symangular/web/app_dev.php/home',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
data:{libelle:val}
})
If you don't want to add this header every time call $http function, you can add it as default config to $httpProvider:
angular
.module('yourModuleName', [])
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
}])
;
For more details about $http configs and how to set default configs, look at Angularjs Documentation
Your approach is a little confused, and therefore very hard to debug.
its good practice (IMO) to separate your api endpoints from the controller action that renders the page. Coupling them together is going to seriously limit the extensibility of your application.
Its possible that you're failing one part of the complex if statement in your controller action; this is making it hard to debug.
Its also good practice when writing an api to provide the client with an idea of what went wrong on a call. (even if its only you accessing the api)
Looking at your code, it also looks like your getting mixed up in processing the request. Your'e validating the submission based upon it being a Product, and asking symfony to process the data on that basis, but then inside your submitted if statement, pulling out the data again..
You can still harness the symfony form validation by decoupling it and submitting this way.
/**
* If your using annotated routing do this, or make the equivelent in your yaml file.
* #Route("/api/product/create", name="api_product_create")
*/
public function productAction(Request $request)
{
$data = json_decode($request->getContent(), true);
if(!$data)
{
// youll want to handle this exception with a listener or somesuch so that it sends back a nice neat message to your client
throw new InvalidArgumentException('Invalid json');
}
$product = new Product();
// create your form as you did before.
$form = $this->createForm(ProductType::class,$product);
// this tells symfony to fill out the form, as if it was submitted conventionally.
$form->submit($data);
// now we can check for valid (you dont need to check submitted, as valid will do that anyway)
if($form->isValid())
{
// persist the new object
$em = $this->getDoctrine()->getManager();
$em->persist($prod);
$em->flush();
// create a new set of return data
$return = [
'status' => 'success',
'productId' => $product->getId(),
];
return new JsonResponse($return, 201);
}
// oops, something went wrong, find out and report it
$return = [
'status' => 'error',
'uri' => $request->getPathInfo(),
'errors' => (string) $form->getErrors(true, false),
];
return new JsonResponse($return, 400);
}
then, in your template, render the url to the endpoint properly.
url: {{ path('api_product_create') }},
this is just an example, and may not totally fit your usecase, but as you can see, once decoupled its much easier to find out what went wrong and where.
Useful resources:
https://knpuniversity.com/screencast/symfony-rest2/validation-errors-test (whilst payed to see the video, the transcript is free)
http://symfony.com/doc/current/form/direct_submit.html
thank you all for ansewring my question.. the informations were so helpfull .. otherwise the solution was to seprate the two actions in symfony controller and adding a request header to the $http method and it works very well .. thank u all

Web API creating new actions always results in 404 errors

I have been trying to expand on my Account Controller for my web api however I cannot seem to get new actions to work. I just want an action that intakes a string. So I wrote my action like this:
Update: This action works if I remove the parameter (String val) now = ()
[AllowAnonymous]
[Route("Stuff")]
public IHttpActionResult Stuff(String val)
{
return Ok();
}
Then in my AngularJS I wrote a function to call into my action
function storeConnID (event, data){
return $http({
url: State.Endpoint + "/api/account/stuff",
method: "POST",
headers: {
'Authorization' : 'Bearer '+ State.User.Access_Token
},
data: {
val: data
}
}).then(function (res) { }, function (err) {
console.log(err);
});
};
The url after it is all formatted is as such:
https://localhost:44375/api/account/stuff
Every other action in my controller works however I cannot create new ones?
Continued research:
Javascript isn't simply sending in a string, it is sending a json object with a key/value pair. The web api action doesn't understand this object when I am looking for a string.
My proposed solution:
[AllowAnonymous]
[Route("Stuff")]
public IHttpActionResult Stuff(Dynamic Data)
{
return Ok();
}
By changing the input to a dynamic type the data can come as any form of object.

How to send multiple parameters in AngularJS $http.post to Web API controller action method

How to send multiple parameters in an angularjs $http.post to web api controller action method.
Below is my code.
AngularJS code
var complexObj = { prop1: "value", prop2: "value" };
var id = 100;
var data = { id: id, complexObj: complexObj };
$http({
method: 'POST',
url: 'http://localhost/api/WebApiController/MethodName',
data: data
}).success(function (data, status) {
//do something...
});
$http.post('http://localhost/api/WebApiController/MethodName', data)
.success(function (data, status) {
//do something...
});
Web API controller
[RoutePrefix("api/WebApiController")]
public class WebApiController: ApiController
{
[Route("MethodName")]
public ReturnValue WebApiAction(string id,ComplexObj complexObj)
{
// process request and return data...
}
}
I am getting below response message in fiddler.
{ "message": "No HTTP resource was found that matches the request
URI 'http://localhost/api/WebApiController/MethodName'.",
"messageDetail": "No action was found on the controller
'WebApiController' that matches the request." }
When I send the complexObj alone, its hitting the web api,but all properties are null or set to default values.
What am I doing wrong? How can I send two or more parameters(both complex objects and string/int) in $http.post? Any help is much appreciated.
Web API doesn't support multiple post parameters in this way.
Your best bet is to roll up Id into ComplexObj and post it as a single parameter.
complexObj.id = id;
var data = complexObj;
Update your signature to take just a single object.
[Route("MethodName")]
public ReturnValue WebApiAction(ComplexObj complexObj)
{
// process request and return data...
}
If you absolutely want to be able to post data like this, consider Rick Strahl's post on creating a custom parameter binder.

actions in $resource in angularjs

I have a webapi back end with the following method in the ProductController :
[HttpGet]
[Route("api/product/FindName")]
public Product FindName(string name){
return name & "Hello "
}
I am trying to make use of $resource in the frontend.
var resource = $resource('api/product/:id', {});
resource.query() will return all items which are exposed in the server side using the GetALL() method. This works fine .
What exactly is the {action} in the $resource does ? I have seen examples for the POST, but what if is set
var resource = $resource('api/product/:id', {}, { FindName: { method: 'GET', params: { name: 'phone' } } });
will this call the method FindName in the backend ? or what exactly it does, I mean the parameter if I set the 'GET' in method.
I am calling as
resource.FindName({ name: 'phone' }, function () {
});
But the backend is not getting fired . i see the call that is being requested to the server from fiddler is
Demo/api/product?name=phone
The resource declaration is incorrect. It should be
var resource = $resource('api/product/:id', {}, { FindName: { method: 'GET', params: { id: 'phone' } } });
This defaults the id placeholder to value phone.
For invocation now you can do
resource.FindName({}, function () { //gets api/product/phone
});
or override id part
resource.FindName({id:'tablet'}, function () { //gets api/product/tablet
});
Resource has a built in GET function that should be able to be used without the need to define the extra FindName action that has been added to $resource.
If you changed the route on your webapi to be
[HttpGet]
[Route("api/product/{name}")]
public Product FindName(string name){
return name & "Hello "
}
Then you could use resource like this to get data back from this route.
var resource = $resource('api/product/:id', {}, {});
resource.get({ id: 'phone' }, function () {
});
If you wanted the name params to match on both you could change :id to :name and in the resource.get change id to name also.
I hope this helps.

Backbone Collection + Instagram API

Hello i have just dived into backbone.
What i am trying to do is make a collection of low_resolution photos from the instagram api feed.
I have model for user that stores all the instagram info like access_token and,
App.Models.Ig_photo({});
And a collection ,
App.Collections.Ig_photos({function() {
model: App.Models.Ig_photo,
url: "https://api.instagram.com/v1/users/self/feed?access_token=",
sync:function (method, model, options) {
options.timeout = 10000; // required, or the application won't pick up on 404 responses
options.dataType = "jsonp";
return Backbone.sync(method, model, options);
},
parse: function( response ) {
return response.data
}
}});
Now i have some issues here, that my collection doesn't get populated when i do fetch and secondly what i wanted was the accesstoken is saved in my another model called user so how do i access it here?
Also it would be great if someone suggests the approach im taking is correct or not. ?
You could add the API key to the collection model:
App.Collections.Ig_photos.access_token = OtherModel.get("access_token");
And use a function for the collection URL:
url: function() {
return "https://api.instagram.com/v1/users/self/feed?access_token=" + this.access_token
},

Resources