I have a json formatted post that arrives in the laravel api controller :
public function update($id) {
$post=Request::all();
return $post;
}
the post logs out to the console:
{id: 1, title: "Quiz1", description: "This is a quiz", level_id: 1, questions: Array[2]}
I would like to use the $post data in the laravel api controller to extract the data from the json object array and update my database.
The angular post is:
$scope.updateQuiz = function(quiz) {
$scope.loading = true;
$http.put('/admin/api/quiz/' + quiz.id, {
quiz
}).success(function(data, status, headers, config) {
$scope = data;
console.log($scope.quiz);
$scope.loading = false;
});
};
The code works in that it grabs the angular data and posts it to Laravel function and then posts back to the console in the angular app.
It is just the extraction of individual data that I cannot do.
This seems to work for individual posts but is rather cumbersome:
Angular:
$http.put('/admin/api/quiz/' + quiz.id, {
title:quiz.title
}).success......
Laravel Api:
$quiz->title = Request::input('title');
Wondering how I can avoid listing out all post objects.Must be something obvious I'm missing!?
Thanks.
Is this what you want ?
public function update($id) {
$post = Post::find($id);
if( !is_null($post ) ){
$post->title= $request->input('title');
$post->description= $request->input('description');
//And so on for all fields...
$post->save();
}
}
Note : it's not present in my example above, but you should validate the values received with the laravel validation. See http://laravel.com/docs/5.0/validation#form-request-validation
If your question was about how you redirect the http request to the controller, you should read the routing chapter of the doc : http://laravel.com/docs/5.0/routing
ex :
$app->group(['namespace' => 'App\Http\Controllers'], function($group){
$group->put('/admin/api/quiz/', 'YourController#update');
});
Related
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
I am new to AngularJS and the question may not be very smart.
I am trying to redirect to a new page with data-binding from Spring Controller.
My requirement is that when I click on a button/hyperlink on a page (say page 1), my Spring Controller performs business and determines which page to display (either page 2 or page 3). The data in the redirected page is populated from Spring Controller during redirection using query params.
My problem is that the page redirects just fine. But I am unable to retrieve the query params in AngularJS, though I can view them in the redirection request URL in browser (Google developer tools).
I have only added the relevant code :
Controller method called from first jsp page (say page1.jsp) to redirect to page2 (pageToRedirectTo.jsp)
In page1.jsp, there is a button that calls the method for page redirection along with form object.
<button ng-click="ctrl.onClickOfPage1ButtonRedirect ()">Page Redirect</button>
app.js
var angularApp = angular.module('angularApp',[]);
AngularJs Controller
this.onClickOfPage1ButtonRedirect = function(){
Page1Service.redirectToNewPage()
.then(
function(d) {
$scope.myVal = d;
var e1 = angular.element(document.getElementById("dir"));
e1.html(d);
$compile(e1.contents())($scope);
},
function(errResponse){
console.error('Error.');
}
);
};
AngularJS Service that sends request to Spring Controller
Page1Service.js
angularApp.factory('Page1Service', ['$http', '$q', function($http, $q){
return {
redirectToNewPage: function() {
return $http.post('/requestMappingUrlFromPage1')
.then(
function(response){
return response.data;
},
function(errResponse){
return $q.reject(errResponse);
}
);
}
};
}]);
Spring Controller
#RequestMapping(value="/requestMappingUrlFromPage1", method = RequestMethod.POST)
public ResponseEntity<Void> redirectToNewPage(){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
List<ResponseDTO> responseDTO = new ArrayList<ResponseDTO>();
//Business logic to populate responseDTO list ....
String responseJson= new Gson().toJson(responseDTO);
UriComponentsBuilder b = UriComponentsBuilder.fromPath("/pageToRedirectTo");
UriComponents uriComponents = b.queryParam("responseDTOList", responseJson).build();
return new ResponseEntity<Void>(headers,HttpStatus.FOUND);
}
Now, when I get the response in Page1Service.js, it displays the response.data as the html content of the page being redirected to. In Google Chrome developer tools, I can see the query parameters :
responseDTOList:[{"parameter1":"123","parameter2":"Name","parameter3":false,"parameter4":false},{"parameter1":"123123","parameter2":"Name1","parameter3":false,"parameter4":false}]
Response received in Page1Service.js
Object {data: "<!DOCTYPE html>
↵<html ng-app="angularApp">
↵<head>
.......
↵</body>
↵
↵</html>", status: 200, config: Object, statusText: "OK"}
Is there a way to retrieve this data?
I have tried using $route.params, but it is undefined. Also, I am not using ng-route. Using $location is also not useful as all my pages are dynamically embedded in the custom dir tag in home page, so $location.absUrl() always gives the home page url.
Any suggestions are much appreciated. Thanks a lot in advance!!
I have added the browser header params that shows the response object in my Query Params. Angular response.data, however, displays just the HTML content, and I am unable to retrieve the query params.
Link to view the Browser headers : browser headers
The idea which pop in my head after examine your problem is that the one way of achieving your target is to convert angularJS page into Thymeleaf page. Its very simple to convert it and your all angularJS code will remain same. Please see Thymeleaf doc for this purpose.
Then simply you can get params in js script like this
<script th:inline="javascript">
/*<![CDATA[*/
var message = [[${message}]];
console.log(message);
/*]]>*/
</script>
Once you got your parms in Javascript then you can easily get into angularJS Controller.
If you are getting Page1Service.js response.data as HTML you can use JSON.parse to parse the content and get data.
it will be helpful to provide ans if you make it more clear "when I get the response in Page1Service.js, it displays the response.data as the html content of the page being redirected to."
I am not sure of it is possible to retrieve response data from query parameters in AngularJS.
However, I solved my problem by retrieving the query params in the GET request of the redirected page in Spring Controller. Then, I am sending it back to Angular Service via the HttpServletResponse header and retrieving it back in AngularJS.
Probably not the ideal solution, but that's the fix I could find in a short period without major restructuring of my code.
Spring Controller for redirection from page1 to page2
#RequestMapping(value="/requestMappingUrlFromPage1", method = RequestMethod.POST)
public ResponseEntity<Void> redirectToNewPage(){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
List<ResponseDTO> responseDTO = new ArrayList<ResponseDTO>();
//Business logic to populate responseDTO list ....
String responseJson= new Gson().toJson(responseDTO);
UriComponentsBuilder b = UriComponentsBuilder.fromPath("/pageToRedirectTo");
UriComponents uriComponents = b.queryParam("responseDTOList", responseJson).build();
return new ResponseEntity<Void>(headers,HttpStatus.FOUND);
}
Redirected Page Controller mapping
#RequestMapping(value="/pageToRedirectTo",method = RequestMethod.GET)
public String getpageToRedirectTo(#RequestParam(required=false, name="responseDTOList")String temp, HttpServletRequest request,HttpServletResponse response) {
try{
if(temp!=null){
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//JSON from String to Object
List<ResponseDTO> objList = mapper.readValue(temp,TypeFactory.defaultInstance().constructCollectionType(List.class,ResponseDTO.class));
if(objList!=null){
String jsonList = new Gson().toJson(objList);
response.setHeader("responseDTOList", jsonList);
}
}
}catch(JsonMappingException jme){
logger.error("JsonMappingException : ", jme);
}catch(JsonParseException jpe){
logger.error("JsonParseException : ", jpe);
}
catch(IOException ioe){
logger.error("IOException : ", ioe);
}catch(Exception e){
logger.error("Error : ", e);
}
return "pageToRedirectTo";
}
Page1Service.js
angularApp.factory('Page1Service', ['$http', '$q', function($http, $q){
return {
redirectToNewPage: function() {
return $http.post('/requestMappingUrlFromPage1')
.then(
function(response){
var customResponse = {};
customResponse.responseDTOList= response.headers('responseDTOList');
customResponse.pageData = response.data;
return customResponse;
},
function(errResponse){
return $q.reject(errResponse);
}
);
}};}]);
AngularJS Controller
this.onClickOfPage1ButtonRedirect = function(){
Page1Service.redirectToNewPage()
.then(
function(d) {
$scope.responseList = d.responseDTOList;
$scope.myVal = d.pageData;
var e1 = angular.element(document.getElementById("dir"));
e1.html(d);
$compile(e1.contents())($scope);
},
function(errResponse){
console.error('Error.');
}
);
};
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.
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]
}
I have a problem. I have this dropdown list :
#Html.DropDownListFor(m => m.SelectCountryId, Model.Countries, #Translator.Translate("PLEASE_SELECT"), new { id = "CountryID", #class = "form-control",ng_model="countryId", ng_change = "LoadRegions(countryId);", #required = "required" })
And i need on ng_change to get into MVC controller that looks like this:
[AllowAnonymous]
public JsonResult GetRegions(int countryId) // return a JsonResult
{
IUserManager manager = UserFactory.GetUserManager(WebConfiguration.DefaultTerminalId);
var model = manager.GetRegions(countryId);
return Json(model, JsonRequestBehavior.AllowGet);
}
This is script in angular:
$scope.LoadRegions = function (countryId)
{
console.log("COUNTRY ID: ", countryId);
$http.post('/app/Account/GetRegions/'+ countryId).then(function (response)
{
alert(response);
});
}
I get country ID but in console i get this error:
POST http://localhost:60789/app/Account/GetRegions/4 500 (Internal Server Error)
The default routing in MVC allows for {controller}/{action}/{id} but your controller is expecting {controller}/{action}/{countryId}.
You can change your call to look like:
GetRegions?countryId=XXX
Or change your method signature to look like:
public JsonResult GetRegions(int id)
Or, if you really want to, you can accommodate this route in your RouteConfig.cs
Edit: I just realized you're calling this with $http.post but everything in your code suggests you want this to be a GET, so I'd change your angular code to $http.get()
From the looks of it there are a few problems in your javascript.
Try the following.
$scope.LoadRegions = function (countryId)
{
var params = {};
params.countryId = countryId;
console.log("COUNTRY ID: ", countryId);
$http.post('/Account/GetRegions/', params).then(function (response)
{
alert(response);
});
}
As you can see you're passing in the params object with the country ID, you are making a call to the POST on the server side also -> Seperate to the angular app folder.