I'm trying to get ExtDirectSpring to work but can't figure out what the URL to the Direct Router shall be.
My controller:
#Controller
#RequestMapping(value = "/sonstiges/extdirect")
#Transactional
public class ExtDirectController {
#RequestMapping(value = "")
public String start() throws Exception {
return "/sonstiges/extdirect";
}
#ExtDirectMethod(value = ExtDirectMethodType.STORE_READ)
public List<String> loadAllMyStuff() {
return Arrays.asList(new String[] {"one", "two"});
}
}
In my JSP I add a provider like this:
Ext.direct.Manager.addProvider({
"type":"remoting", // create a Ext.direct.RemotingProvider
"url":"/fkr/app/controller/extjs/remoting/router", // url to connect to the Ext.Direct server-side router.
"actions":{ // each property within the actions object represents a Class
"ExtDirectController":[
// array of methods within each server side Class
{
"name":"loadAllMyStuff", // name of method
"len":0
},
{
"name":"myTestFunction", // name of method
"len":0
}
]
},
"namespace":"FKR"// namespace to create the Remoting Provider in
});
... and use the following store to populate a grid:
store: {
model: 'Company',
remoteSort: true,
autoLoad: true,
sorters: [
{
property: 'turnover',
direction: 'DESC'
}],
proxy: {
type: 'direct',
directFn: FKR.ExtDirectController.loadAllMyStuff
}
}
Loading the page, a request to http://localhost:8080/fkr/app/controller/extjs/remoting/router is send, but not to my loadAllMyStuff- function. My guess is that the URL to the direct router is wrong.
What is the correct URL to the router?
EDIT: I just figured out that the method router in RouterController expects the parameters extAction and extMethod, but with the given code the parameters action and method are sent. That seems to be odd ...
Related
I'm creating frontend for my backend using Angular and having troubles calling POST API using HTTPClient. Below is my code:
article.service.ts
#Injectable()
export class ArticleService {
url = "//localhost:8080/deleteArticle";
constructor(private http: HttpClient) { }
deleteArticle(article: Article): Observable<HttpResponse<Article>> {
return this.http.post<Article>(this.url, article,
{
observe: 'response'
}
);
}
}
article.component.ts
#Component({
selector: 'app-article',
templateUrl: './article.component.html'
})
export class AcrticleComponent implements OnInit {
articleForm: FormGroup;
constructor(private formBuilder:FormBuilder, private articleService: ArticleService) {
}
ngOnInit() {
this.articleForm = this.formBuilder.group({
title: ['', [ Validators.required ] ]
});
}
onFormSubmit() {
let article = this.articleForm.value;
this.deleteArticle(article);
this.articleForm.reset();
}
deleteArticle(article: Article) {
this.articleService.deleteArticle(article).subscribe(
article => {
console.log(article);
},
err => {
console.log(err);
}
);
}
get title() {
return this.articleForm.get('title');
}
}
Spring Controller:
#PostMapping("/deleteArticle")
#CrossOrigin(origins = "http://localhost:4200")
public String deleteArticle(#RequestParam(value = "id") String id) {
deleteService.deleteArticle(id);
}
After entering the title and hitting submit, it returns this error (status 404):
{error: "Collection 'localhost:8080' not found"}
Can you show me what I did wrong and how my angular frontend couldn't find my backend endpoint?
The url needs to be complete.
include the http:
But I would suggest using the webpack dev server proxy.
If you put all your apis under the /api/ url then you can proxy all calls to /api/* back to your spring backend.
then when you launch your project you do the same there and proxy in /api/* using nginx or similar.
You can read more about how to proxy using angular-cli here https://github.com/angular/angular-cli/wiki/stories-proxy
Make sure you are spring application is running on the same port as 8080 and add http before your url. I hope this not your problem,but try like this..
#Injectable()
export class ArticleService {
url = "http://localhost:4200/deleteArticle";//add http here
constructor(private http: HttpClient) { }
deleteAccount(article: Article): Observable<HttpResponse<Article>> {
return this.http.post<Article>(this.url, article,
{
observe: 'response'
}
);
}
}
EDIT
Add a class Like Article and get the Id which you are sending from Article class of Angular Service
#PostMapping("/deleteArticle")
#CrossOrigin(origins = "http://localhost:4200")
public String deleteArticle(#RequestParam() Article article,
RedirectAttributes redirectAttributes) {
deleteService.deleteArticle(article.id, redirectAttributes);
}
Here i'm new to mvc core2.0 please help me why my Routing Is not working
My Routing Class
public static class ApplicationRoteProfiler
{
public static void Routeing(IRouteBuilder builder)
{
builder.MapRoute("route1", "", new
{
Controllers = "Department",
Action = "Add",
});
builder.MapRoute("route2", "Department/Add", new
{
Controllers = "Department",
Action = "Index"
});
}
This class file i register in startup.config file
public void Configure(IApplicationBuilder app)
{
app.UseStaticFiles();
app.UseMvc();
app.UseMvcWithDefaultRoute();
app.UseMvc(routes =>
{
ApplicationRoteProfiler.Routeing(routes);
});
}
When i hit my server as http://localhost:1588/Department/Add its should redirect to Department/Index But its hitting Department/Add
Should it be just Controller not Controllers??
builder.MapRoute("route1", "", new { controller = "department", action = "index" });
My 2 cents
You shouldn't use app.UseMvcWithDefaultRoute() and app.UseMvc() at the same time. You only need to pick 1 of them.
I don't see benefits of using a static class to configure routing for MVC. You can just put all the route configurations right there inside UseMvc lamba function. Also I don't think you need to put customized route specifically for your "route1" as it follows the standard MVC routing convention.
app.UseMvc(routes =>
{
// The order of these routes matters!
routes.MapRoute(
name: "route2",
template: "department/add",
defaults: new { area = "", controller = "department", action = "index" });
routes.MapRoute(
name: "default",
template: "{controller=home}/{action=index}/{id?}");
}
You can also return RedirectToAction("index"); inside your Department controller Add method so whenever /deparment/add route is hit, it redirects to /deparment/index, assuming you have the default MVC routing setup, either use the "default" route I put on #2, or use UseMvcWithDefaultRoute(). That way you don't need to create custom routes just for redirecting.
public class DepartmentController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult Add()
{
return RedirectToAction("index");
}
}
I am trying to retrieve data from a WebApi project I have created. I have build a new Angular 2 application, which going to get this data through an Api call.
Already have made the data ready in the WebApi project. If I use postman to call the Api, I get data like this example:
[
{
"Id": 1,
"BookingNr": "123456789",
"OutboundDate": "2016-02-05T00:00:00",
"ReturnDate": "2016-04-04T00:00:00",
"Route": "Oslo - Stockholm",
"Passengers": "1 Adult and 1 Child",
"VehicleType": "Car 1.85m x 4.5m"
},
{
"Id": 2,
"BookingNr": "234567891",
"OutboundDate": "2016-03-05T00:00:00",
"ReturnDate": "2016-04-04T00:00:00",
"Route": "Stockholm - Oslo",
"Passengers": "2 Adult and 1 Child",
"VehicleType": "Car 1.85m x 4.5m"
}
]
In my angular 2 project, I have a main component, which calls a service to get the data from the api.
Main component:
#Component({
selector: 'reservation-component',
providers: [...FORM_PROVIDERS, BookingsService],
directives: [...ROUTER_DIRECTIVES, CORE_DIRECTIVES, BookingsListComponent ],
styles: [`
agent {
display: block;
}
`],
pipes: [],
template: `
***No Html in this example***
`,
bindings: [BookingsService],
})
#Injectable()
export class BookingsComponent {
bookings: Array<amendmentBookings> = [];
constructor(public bookingsService: BookingsService) {
this.bookings = this.bookingsService.getBookings();
}
}
Then there is the Service, which makes the call.
Service
#Injectable()
export class BookingsService {
constructor(private router: Router, public http: Http) {
console.log('Booking Service created.', http);
}
getBookings(): Array<amendmentBookings> {
var bookingsRetrieved: Array<amendmentBookings>
this.http.get('http://localhost:55350/api/bookings')
.map(res => res.json())
.map((bookings: Array<any>) => {
let result: Array<amendmentBookings> = [];
if (bookings) {
bookings.forEach(booking => {
result.push(
new amendmentBookings(
booking.bookingNumber,
new Date(booking.outboundDate),
new Date(booking.returnDate),
booking.route,
booking.passengers,
booking.vehicleType))
});
}
return result;
}).subscribe(data => {
bookingsRetrieved = data;
console.log(bookingsRetrieved)
},
err => console.log(err));
return bookingsRetrieved;
}
}
export class amendmentBookings {
constructor(
public bookingNumber: string,
public outboundDate: Date,
public returnDate: Date,
public route: string,
public passengers: string,
public vehicleType: string
) { }
}
When I try to call it, I get the following error:
XMLHttpRequest cannot load http://localhost:55350/api/bookings. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
Have tried to search for the problem, but can only find that something is blocking the request, but no solution for it..
This is how my bookingsController looks like in Visual Studio (I'm using entity framework)
BookingController
public class BookingsController : ApiController
{
private BookingsContext db = new BookingsContext();
// GET: Bookings
public IEnumerable<Booking> Get()
{
return db.Bookings.ToList();
}
}
You need to enable CORS on your Web API if you want to be able to call it from javascript code hosted on a different domain.
So basically in your Web API bootstrap script you would call:
config.EnableCors();
and then decorate your controller with the proper attribute:
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class BookingsController : ApiController
{
...
}
Of course enabling CORS for all domains (*) comes with its security implications so you might want to selectively enable it only for the domain on which your javascript calling code is hosted.
I have my first Web API working, but the even when I call it and pass an an id is gets routed to the method that has no arguments.
Here is my controller code:
public class ChartController : ApiController
{
Chart[] _charts = new Chart[]
{
new Chart { Name = "Chart 1" },
new Chart { Name = "Chart 2" },
new Chart { Name = "Chart 3" }
};
// GET api/chart
[Route("api/chart")]
public IEnumerable<Chart> Get()
{
return _charts;
}
// GET api/chart/{id}
[Route("api/chart/{id}")]
public IEnumerable<Chart> Get(int chartId)
{
Chart[] charts = new Chart[]
{
Charts.Database.ChartsDB.GetChart(chartId)
};
return charts;
}
}
Here is my routing in my global.asax
RouteTable.Routes.MapHttpRoute(
name: "ChartApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
This is my request uri
http://localhost:42311/api/chart
And the results
[
{
"Name": "Chart 1"
},
{
"Name": "Chart 2"
},
{
"Name": "Chart 3"
}
]
When I change the uri to
http://localhost:42311/api/chart/1
I get the same results, as both calls are routed to
public IEnumerable<Chart> Get()
What am I doing wrong?
Please note that WebApi works based on reflection this means that your curly braces {vars} must match the same name in your methods.
Therefore to match this api/chart/{id} your method needs to be declare like this:
[Route("api/chart/{chartId}"), HttpGet]
public IEnumerable<Chart> Get(int chartId)
return userId;
}
Where the parameter {id} was replaced by chartId.
Another option can be:
[Route("api/chart/{id}"), HttpGet]
public IEnumerable<Chart> Get(int id)
return userId;
}
If you want to read more about this Routing Rules here is similar post on this;
WebApi Routing Configuration
I just started using rest library wrote by Phil Sturgeon. I started using it by writing some simple examples. I short of get 'post' and 'get' work, but not for put and delete. I have some questions based on the code below.
// a simple backbone model
var User = Backbone.Model.extend({
urlRoot: '/user',
defaults:{
'name':'John',
'age': 17
}
});
var user1 = new User();
//user1.save(); // request method will be post unless the id attr is specified(put)
//user1.fetch(); // request method will be get unless the id attr is specified
//user1.destroy(); // request method will be Delete with id attr specified
In my CI REST controller
class User extends REST_Controller
{
public function index_get()
{
echo $this->get(null); //I can see the response data
}
public function index_post()
{
echo $this->post(null); //I can see the response data
}
public function index_put()
{
}
public function index_delete()
{
}
}
Basically, the get and post in the controller will be called when I save a model or fetch a model. With a id specified in the model, I can make a put or delete request to the server using model.save() and model.destroy(). however, I got a server error. it looks like index_put or index_delete can not be called. does anyone know How I can handle:
put request in the controller
delete request in the controller
get a single record with id specified
From the git, I only saw him to list index_post and index_put. there is no index_put and index_delete demo. should anyone can help me out? thanks
I faced the same exact problem, it looks like that DELETE, PUT, PATCH methods are not fully supported by browsers/html/server yet. You may want to look at this stack overflow question: Are the PUT, DELETE, HEAD, etc methods available in most web browsers?
A simple solution would be to change the methodMap of backbone line 1191 to the following:
// Map from CRUD to HTTP for our default `Backbone.sync` implementation.
var methodMap = {
'create': 'POST',
'update': 'POST', //'PUT',
'patch': 'POST', //'PATCH',
'delete': 'POST', //'DELETE',
'read': 'GET'
};
and then include the action type as an attribute of the model
var Person = Backbone.Model.extend({
defaults:{
action_type : null,
/*
* rest of the attributes goes here
*/
},
url : 'index.php/person'
});
now when you want to save a model, do the following
var person = new Person({ action_type: 'create' });
person.set( attribute , value ); // do this for all attributes
person.save();
in the application/controllers folder you should have a controller called person.php with class named Person extending REST_Controller, that has the following methods:
class Person extends REST_Controller {
function index_get() { /* this method will be invoked by read action */ }
/* the reason those methods are prefixed with underscore is to make them
* private, not invokable by code ignitor router. Also, because delete is
* might be a reserved word
*/
function _create() { /* insert new record */ }
function _update() { /* update existing record */ }
function _delete() { /* delete this record */ }
function _patch () { /* patch this record */ }
function index_post() {
$action_type = $this->post('action_type');
switch($action_type){
case 'create' : $this->_create(); break;
case 'update' : $this->_update(); break;
case 'delete' : $this->_delete(); break;
case 'patch' : $this->_patch(); break;
default:
$this->response( array( 'Action '. $action_type .' not Found' , 404) );
break;
}
}
}
Having said that, this solution is an ugly one. If you scroll up in the backbone implementation, you will find the following code at line 1160:
// For older servers, emulate HTTP by mimicking the HTTP method with `_method`
// And an `X-HTTP-Method-Override` header.
if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
params.type = 'POST';
which means you need to set the emulate options of backbone configurations. add the following lines to your main.js
Backbone.emulateHTTP = true;
Backbone.emulateJSON = true;
To test the effect of that, I created a simple model and here are the results
you need a controller called Api in applications/controllers folder, in a file named api.php
<?php defined('BASEPATH') OR exit('No direct script access allowed');
require_once APPPATH.'/libraries/REST_Controller.php';
class Api extends REST_Controller
{
function index_get()
{
$this->response(array("GET is invoked"));
}
function index_put()
{
$this->response(array("PUT is invoked"));
}
function index_post()
{
$this->response(array("POST is invoked"));
}
function index_patch()
{
$this->response(array("PATCH is invoked"));
}
function index_delete()
{
$this->response(array("DELETE is invoked"));
}
}
and in your js/models folder, create a model called api_model.js
var Api = Backbone.Model.extend({
defaults:{
id: null,
name: null
},
url: "index.php/api/"
});
var api = new Api();
api.fetch({ success: function(r,s) { console.log(s); } }); // GET is invoked
api.save({},{ success: function(r,s) { console.log(s); } }); // POST is invoked
//to make the record old ( api.isNew() = false now )
api.save({id:1},{ success: function(r,s) { console.log(s); } }); // PUT is invoked
api.destroy({ success: function(r,s) { console.log(s); } }); //DELETE is invoked
I don't know how to do patch, but hope this helps.
Edit
I found out how to do patch, which is not included in the REST implementation of code ignitor. In REST_Controller line 39, you will find the following,
protected $allowed_http_methods = array('get', 'delete', 'post', 'put');
you need to add 'patch' at the end, to accept this method, also, after doing that add this code
/**
* The arguments for the PATCH request method
*
* #var array
*/
protected $_patch_args = array();
also, you need to add the following code to parse patch arguments:
/**
* Parse PATCH
*/
protected function _parse_patch()
{
// It might be a HTTP body
if ($this->request->format)
{
$this->request->body = file_get_contents('php://input');
}
// If no file type is provided, this is probably just arguments
else
{
parse_str(file_get_contents('php://input'), $this->_patch_args);
}
}
Now, according to backbone docs, you need to pass {patch: true} to send a PATCH method, when you call the following line, you execute a patch:
api.save({age:20},{patch: true, success: function(r,s) { console.log(s); } });
// PATCH is invoked