I am new to Scala/Play Framework.
Currently, I am trying to call a Scala function from my html page: test.scala.html and pass the hash parameters to the Scala function.
I added the following lines to routes:
GET /hello controllers.Application.test
POST /hello controllers.Application.hello
In my test.scala.html I have:
#params = { window.location.hash }
#helper.form(action = routes.Application.hello) {
}
And my hello function is defined as:
def hello() = Action {
Ok("Hello !")
}
I am completely confused by the concept of routing and # so I am not too sure which part I did right and which part I did wrong. Please point out my mistakes.
Thanks in advance.
If the function is returning an action, not content to be displayed formatted inside view (HTML), you may want to route request to this action, from a link click or a form submit, to url configured in routing (aka /hello).
To add a parameter you need to either add it as url query string (e.g. for a link → /hello?p=1), or with an input/field for a form (e.g. <input type="text" name="p" value="1" />).
You can use reverse routing to get URL to call configured action. For example for a form POST to hello: <form action="#routes.MyController.hello()" method="POST">.... In this case you will need to look at form mapping, to extract parameters from request.
1) Concept of routing
The main purpose of this routing is simply to translate each incoming HTTP request to an Action in any of your Controller. By Reverse Routing its simply let you use the right part, controllers.Application.hello, in your HTML/Controller/else.
So, for your 2 URLs above, it's likely to say that if there is a request /hello with method GET then it will go to Application controller and test method. If you don't understand the role of each Routing method, please read this documentation..
2) the magic # character
# is a character that you can use in your HTML file if you need to use the Scala code or variables. It's like you can combine PHP code in your HTML file, if you're a PHP developer.
Here is the full-documentation of what you can do with this # character.
3) pass the hash to the controller
To this specific case the simplest way would be passing the value trough a form:
#helper.form(action = routes.Application.hello) {
#helper.inputText(myForm("username"), 'id -> "username", 'size -> 30, 'value -> 'value here' )
}
However, if you're a new Play developer, then I'm afraid you need to read about Form Submission and Form Helper in Play Framework..
Related
I'm currently trying to connect an Extjs form to a Play! Scala backend.
I have no problem receiving the request, but
FormName.bindFromRequest.get returns to me None .
I'm able to find the data generated via submitting from Extjs in the POST request in request.request.body.data (the first request object is generated by SocialSecure's controller), whereas normally the data bound to the form would be found in request.request.body.data.elems
I think Extjs's eschewal of using <form> in their inserted HTML is what causes me this problem, but I'd still like to take advantage of Extjs's nice form verification UI.
Does Play! or Scala have any resources for modifying a request after the server has received it?
More info
This is the method my /requestAudit cuurently points to after a POST request:
def requestAudit = SecuredAction(WithProvider("google")) { // SecureSocial syntax
implicit request => { // let's call this line 0'
println(request.request.body.asFormUrlEncoded) // let's call this line 1'
println(request.body.asText) // let's call this line 2'
newAuditForm.bindFromRequest.fold(
errors => BadRequest(views.html.error(newAuditForm))
success => { /*insert the object into my db*/ }
) } }
Ext.js request
When I'm debugging in Eclipse with an Ext.js form, the Variables window shows: (click for closeup)
where the form values are located in request.body.data.key1, request.body.data.key2, etc
Bootstrap form request
On the other hand, the request for Bootstrap has the values stored in request.body.data.elems
#2manyprojects 's suggestion set me on the right path:
newAuditForm.bindFromRequest(
(request.request.body.asFormUrlEncoded).getOrElse(Map()))
.fold( ... )
worked.
I was still getting form binding errors after changing my code to this, and then I discovered a typo in the name property of one of my Ext.js form fields. The name of the field must be the same on both the UI and the Play Form.
My web application will be triggered from an external system. It will call one request path of my app, but uses different query parameters for different kinds of requests.
One of the parameters is the "action" that defines what is to be done. The rest of the params depend on the "action".
So I can get request params like these:
action=sayHello&user=Joe
action=newUser&name=Joe&address=xxx
action=resetPassword
...
I would like to be able to encode it similarly in the routes file for play so it does the query param based routing and as much of the validation of other parameters as possible.
What I have instead is one routing for all of these possibilities with plenty of optional parameters. The action processing it starts with a big pattern match to do dispatch and parameter validation.
Googling and checking SO just popped up plenty of samples where the params are encoded in the request path somehow, so multiple paths are routed to the same action, but I would like the opposite: one path routed to different actions.
One of my colleagues said we could have one "dispatcher" action that would just redirect based on the "action" parameter. It would be a bit more structured then the current solution, but it would not eliminate the long list of optional parameters which should be selectively passed to the next action, so I hope one knows an even better solution :-)
BTW the external system that calls my app is developed by another company and I have no influence on this design, so it's not an option to change the way how my app is triggered.
The single dispatcher action is probably the way to go, and you don't need to specify all of your optional parameters in the route. If action is always there then that's the only one you really need.
GET /someRoute controller.dispatcher(action: String)
Then in your action method you can access request.queryString to get any of the other optional parameters.
Note: I am NOT experienced Scala developer, so maybe presented snippets can be optimized... What's important for you they are valid and working.
So...
You don't need to declare every optional param in the routes file. It is great shortcut for type param's validation and best choice would be convince 'other company' to use API prepared by you... Anyway if you haven't such possibility you can also handle their requests as required.
In general: the dispatcher approach seems to be right in this place, fortunately you don't need to declare all optional params in the routes and pass it between actions/methods as they can be fetched directly from request. In PHP it can be compared to $_GET['action'] and in Java version of Play 2 controller - DynamicForm class - form().bindFromRequest.get("action").
Let's say that you have a route:
GET /dispatcher controllers.Application.dispatcher
In that case your dispatcher action (and additional methods) can look like:
def dispatcher = Action { implicit request =>
request.queryString.get("action").flatMap(_.headOption).getOrElse("invalid") match {
case "sayHello" => sayHelloMethod
case "newUser" => newUserMethod
case _ => BadRequest("Action not allowed!")
}
}
// http://localhost:9000/dispatcher?action=sayHello&name=John
def sayHelloMethod(implicit request: RequestHeader) = {
val name = request.queryString.get("name").flatMap(_.headOption).getOrElse("")
Ok("Hello " + name )
}
// http://localhost:9000/dispatcher?action=newUser&name=John+Doe&address=john#doe.com
def newUserMethod(implicit request: RequestHeader) = {
val name = request.queryString.get("name").flatMap(_.headOption).getOrElse("")
val address = request.queryString.get("address").flatMap(_.headOption).getOrElse("")
Ok("We are creating new user " + name + " with address " + address)
}
Of course you will need to validate incoming types and values 'manually', especially when actions will be operating on the DataBase, anyway biggest part of your problem you have resolved now.
I have a web application in Play. The web application consists of several pages. In every page there is a small flag that enables the user to change the language (locale) from german to english and back.
I handle this with a redirect to referer:
def referer(implicit request: Request[AnyContent]) =
request.headers.get(REFERER).getOrElse(mainUrl)
def locale(l: String) = Authenticated { user =>
implicit request =>
Redirect(referer).withCookies(Cookie(LANG, if (l == "de" || l == "en") l else "de"))
}
It is working fine. Well, at least for GET requests.
I have a specific page where the user has to input data in a form. This form is then POSTed to the server. Were errors found, the form is displayed again with the error messages, as usual. Now, if the user wants to change the language (by clicking on the flag), the redirect to referer does not work, because it tries to use a GET request, and Play complains that a GET route does not exist for this method (which is true).
I am solving this by caching the form and defining another method where the form is taken from the cache:
# User data is POSTed to the server
POST /create/insert controllers.MyCreate.insert()
# After a redirect the cached form is displayed again
GET /create/insert controllers.MyCreate.insertGet()
It works, but I don't like this solution. It does not seem normal to have to create another entry in the routes and another method just to adress this problem. I would need to add this hack for every POST route in my application!
Is there a more elegant solution to this?
You could change it into something like this (untested):
def changeLang(lang:String, returnUri:String) = Action {
Redirect(returnUri)
.withCookies(Cookie(LANG, if (lang == "de" || lang == "en") lang else "de"))
}
In you template you would output the route to changeLang in the link, you can get the uri via the request
#routes.Application.changeLang("en", request.uri).url
I suggest you make request implicit in your action and define it as implicit in your template so you don't need to pass it on to each template.
// in the controller
def myUrl = Action { implicit request =>
Ok(views.html.myTemplate("something"))
}
// in the template
#(title:String)(implicit request:play.api.mvc.RequestHeader)
Edit
As for the POST requests, it common (for these types of framework) to have POST requests simple handle stuff and then redirect to another page. The usual flow is like this:
Form submits to a handler
Handler does something with the form information
Handler redirects to a page
An example:
// Hooked up to a GET route
def edit(id:Long) = Action {
// render the view with a form that displays the element with given id
// if the flash scope contains validation information, use that in display
}
// Hooked up to a POST route
def editHandler = Action {
// validate the form
// if validation succeeds
// persist the object
// redirect to edit
// else
// put the form information into the flash scope
// put any validation messages into the flash scope
// redirect to edit
}
If you do not want to use this flow you need to have both a GET and POST route anyway. The user might do a page reload on the resulting page.
Lets say I have a form with method=POST on my page.
Now this form has some basic form elements like textbox, checkbox, etc
It has action URL as http://example.com/someAction.do?param=value
I do understand that this is actually a contradictory thing to do, but my question is will it work in practice.
So my questions are;
Since the form method is POST and I have a querystring as well in my URL (?param=value)
Will it work correctly? i.e. will I be able to retrieve param=value on my receiving page (someAction.do)
Lets say I use Java/JSP to access the values on server side. So what is the way to get the values on server side ? Is the syntax same to access value of param=value as well as for the form elements like textbox/radio button/checkbox, etc ?
1) YES, you will have access to POST and GET variables since your request will contain both. So you can use $_GET["param_name"] and $_POST["param_name"] accordingly.
2) Using JSP you can use the following code for both:
<%= request.getParameter("param_name") %>
If you're using EL (JSP Expression Language), you can also get them in the following way:
${param.param_name}
EDIT: if the param_name is present in both the request QueryString and POST data, both of them will be returned as an array of values, the first one being the QueryString.
In such scenarios, getParameter("param_name) would return the first one of them (as explained here), however both of them can be read using the getParameterValues("param_name") method in the following way:
String[] values = request.getParameterValues("param_name");
For further info, read here.
Yes. You can retrieve these parameters in your action class.
Just you have to make property of same name (param in your case) with there getters and setters.
Sample Code
private String param;
{... getters and setters ...}
when you will do this, the parameters value (passed via URL) will get saved into the getters of that particular property. and through this, you can do whatever you want with that value.
The POST method just hide the submitted form data from the user. He/she can't see what data has been sent to the server, unless a special tool is used.
The GET method allows anybody to see what data it has. You can easily see the data from the URL (ex. By seeing the key-value pairs in the query string).
In other words it is up to you to show the (maybe unimportant) data to the user by using query string in the form action. For example in a data table filter. To keep the current pagination state, you can use domain.com/path.do?page=3 as an action. And you can hide the other data within the form components, like input, textarea, etc.
Both methods can be catched in the server with the same way. For example in Java, by using request.getParameter("page").
I am trying to figure out how to do a redirect within a controller action in Play (2.0) using Scala.
The redirect using
Redirect(routes.Application.index)
works just fine.
What I cannot figure out from the docs, API, or Google is how to add parameters to the call.
I am coming from Grails where this could be done easily as follows:
redirect action: "index", params: ["key": "value"]
.
The only way I have found is to call Redirect using a string url and a query string, which seems awkward.
Basically I would like to make use of Redirect(Call) somehow, but I do not how to create the Call object using reverse routing.
Am I missing something/not getting the concept in Play/Scala?
Thanks in Advance!
Ellou'
A route is just a function, so you can pass arguments as usual:
// Redirect to /hello/Bob
def helloBob = Action {
Redirect(routes.Application.hello("Bob"))
}
This snippet comes from http://www.playframework.org/documentation/2.0/ScalaRouting (at the bottom)
You can also avoid creating another function just for this in your controller. In your route config, you can simply add something like this:
GET /google #controllers.Default.redirect(to = "http://google.com")