missing arguments for method apply... Play Framework 2.4 compilation error - scala

Compilation error: missing arguments for method apply in class newPost;
follow this method with `_' if you want to treat it as a partially applied function
I don't understand how template handling methods have to look like and what complier require of me.
https://github.com/flatlizard/blog
controller:
def addPost = Action{ implicit request =>
Ok(views.html.newPost(postForm))
}
def createPost = Action { implicit request =>
postForm.bindFromRequest.fold(
hasErrors => BadRequest,
success => {
Post.create(Post(new Date, success.title, success.content))
Ok(views.html.archive("my blog", Post.all))
})
}
routes:
GET /archive/new controllers.Application.addPost
POST /archive controllers.Application.createPost
view:
#(postForm: Form[Post])(content: Html)(implicit messages: Messages)
#import helper._
#form(routes.Application.createPost) {
#inputDate(postForm("date"))
#textarea(postForm("title"))
#textarea(postForm("content"))
<button id="submit" type="submit" value="Submit" class="btn btn-primary">Submit</button>
}
UPDATE
I solved problem adding the following imports in controller file:
import play.api.i18n.Messages.Implicits._
import play.api.Play.current
See Play 2.4 migration:
https://www.playframework.com/documentation/2.4.x/Migration24#I18n

Compilation error
Your view expects three parameters to be passed, but you are passing only one. To solve your compilation error, change the signature in your view from#(postForm: Form[Post])(content: Html)(implicit messages: Messages) to #(postForm: Form[Post])(implicit messages: Messages).
Parameters and views
The second parameter in your example (content: Html) is used when you combine several views:
index.scala.html
#(text: String)
#main("Fancy title") {
<div>#text</div>
}
main.scala.html
#(title: String)(content: Html)
<html>
<head>
<title>#title</title>
</head>
<body>
#content
<body>
</html>
Call in controller
Ok(views.html.index("Some text"))
In this example you are passing "Some text" to index view. Index view then calls main view passing another two parameters. title and content, where content is the html in between the curly braces of index.scala.html (<div>#text</div>)
Finally implicit parameters: (implicit messages: Messages) must be somewhere in scope to be passed implicitly to your view. For example like this in your controller:
def addPost = Action{ implicit request =>
implicit val messages: Messages = ...
Ok(views.html.newPost(postForm))
}

I solved problem adding the following imports in controller file:
import play.api.i18n.Messages.Implicits._
import play.api.Play.current
See Play 2.4 migration: https://www.playframework.com/documentation/2.4.x/Migration24#I18n
Update
Actually this is a bad way cause here used Play.current which will become deprecated soon. Here another solution using dependency injection:
routes:
GET /archive/new #controllers.Application.addPost
POST /archive #controllers.Application.createPost
controller:
class Application #Inject() (val messagesApi: MessagesApi)
extends Controller with I18nSupport{
...
}
https://www.playframework.com/documentation/2.4.x/ScalaDependencyInjection

Related

Working aroung passing an Implicit parameter to every single template

I'm doing some work with PlayFramework templates, but I have encountered a problem. We're using play's helpers which requires Messages (imported from play.api.i18n). Everything was ok until our Designer wanted to have login form in form of Modal... Because it'll be appended to every single template, we'll need to add that messages parameter everywhere - which is ugly IMHO.
Is there a way to work that around? Passing it everywhere would mean that I have to Inject() it everywhere, even if it's needed only to be passed to shut the typechecker.
Sample Page:
#(project: model.Project)(implicit request: Request[AnyContent], messages: Messages)
#main(project.name){
<h1>#project.name</h1>
<ul>
#for(member <- project.members) {
<li>#member</li>
}
</ul>
}{}
Fragment of Main template:
#(title: String)(content: Html)(additionalImport: Any)(implicit req: Request[AnyContent], messages: Messages)
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
#* this call actually needs that param. *#
#header.navbar()
<div class="container">
#req.flash.get("error").map { error =>
<div class="flash-error">#error</div>
}
#content
</div>
</body>
</html>
The Form:
#import model.UserLoginData
#(loginForm: Form[UserLoginData])(implicit req: Request[AnyContent], messages: Messages)
#helper.form(action = routes.AuthenticationController.login()) {
#loginForm.globalErrors.map { error =>
<div class="error">#error.message</div>
}
#helper.inputText(loginForm("login"))
#helper.inputPassword(loginForm("password"))
<input type="submit" value="Zaloguj"/>
}
Zapomniałem hasła
Here I see two work arounds. Unfortunately, I am not able to test them now, but I believe they will both work.
Get rid of the messages parameter from the form template. Use Play.current.injector.instanceOf[MessagesApi] to get MessagesApi implementation just inside the template (here is a question about accessing injector without an #Inject annotation). Then you may call the method preferred(Http.RequestHeader request):Messages to get a Messages instance, and then you need to explicitly pass this to a helper method.
If you just want to get rid of injection and you don't mind passing an implicit messages parameter to every single template, you may implement your own version of the I18nSupport trait. Here I mean that you usually write the controller in the following way:
class SomeController #Inject()(val messagesApi: MessagesApi) extends Controller with I18nSupport. The messagesApi val overrides the same value of the I18nSupport trait. You may extend this trait with your own MyI18Support trait, and inject MessagesApi inside it (UPD: you may either #Iinject or use Play.current.injector). Then you will only need to write the controller as follows: class SomeController extends Controller with MyI18nSupport.

How to access controller variable without passing to Play html

Is it possible to access Play Framework scala contoller variables wihout passing to scala.html template?
For example my controller code as below,
def index = Action { request =>
val orgId = '12132132'
Ok(views.html.index(request))
}
My index.scala.html as below,
#(implicit request: RequestHeader)
#main("Test") {
I want to access controller "orgId" variable here wihtout passing here.
}
Here is my main.scala.html,
#(title: String)(content: Html)
<html lang="en">
<head>
<title>#title</title>
</head>
<body>
#content <!-- index.html placed here -->
</body>
<div>
Here I have bootstrap side menu and I want to display controller variable here without passing to main.scala.html templete.
</div>
</html>
Thanks.
You cannot do it since it private for the function. No other function can access it (even not in the same class).
If you are using object as instance of the controller (instead of class) and you use value of the object itself then you can do it, but It HIGHLY NOT recommended.
e.g.
object MyController extends controller {
val orgId = '12132132'
def index = Action { request =>
Ok(views.html.index(request))
}
...
}
#(implicit request: RequestHeader)
#main("Test") {
I want to access controller "#{MyController.orgId}" variable here without passing here.
}
If you need to pass some data that isn't depend on the request, meaning it can be value of the object, then it also may be outside the controller. So you can create an object that will hold those values, and access them.
Technically it the same as use the controller, but logically it better separation.

Lift 2.6: How to append a NodeSeq rather than using SetHtml()

I use SetHtml() all the time to swap chunks of HTML as part of the return trip of an ajax call, ie. when my "Edit Item" ajax call returns, I swap the contents of with form elements representing the "Item" to be edited.
Now I'm trying to add a new item to a list (so that "Item 2" appears as the next li under "Item 1"). My html looks like (this is a greatly simplified version) this:
<div data-lift="form.ajax">
<div data-lift="JsCmdTest">
<test:submitbutton></test:submitbutton>
<ul id="targetdiv">
<li>Item 1</li>
</ul>
</div>
</div>
and my Lift code looks like this
class JsCmdTest extends StatefulSnippet
{
def dispatch = { case "render" => render }
def bindStuff(ns: NodeSeq): NodeSeq =
{
bind("test", ns,
"submitbutton" -> SHtml.ajaxButton("Go", ()=> {
val newLi = Jx(<div>Item 2</div>)
(ElemById("targetdiv") ~> JsFunc("appendChild", newLi.toJs)).cmd
})
)
}
def render: (NodeSeq)=>NodeSeq = (ns: NodeSeq) => {
bindStuff(ns)
}
}
When I run this, the ajax call is fired, and the response looks fine, but I get the following error in the browser console:
The server call succeeded, but the returned Javascript contains an error: NotFoundError: Failed to execute 'appendChild' on 'Node': The new child element is null.
WANTED: a way to append replacement HTML to an existing < ul >. I feel like the way I'm going about appending seems way more esoteric than probably needed, but i haven't found any other way to do it.
Thanks in advance!
you're using a very old syntax for binding. If I am not mistaken, a new way for bindings was introduced somewhere in lift-2, and it is the recommended one since somewhere in lift-2.2. (I'll write the syntax below.)
JsFunc is an anonymous function, like def local(a: A): B. You don't need to send anonymous function, you can send the code directly. (See below.)
So, I recommend something like this:
import net.liftweb.http.js.{JsExp, JsCmd, JsCmds}
import net.liftweb.http.js.jquery.JqJE.{JqAppend, JqId}
def render = {
val appendJs: JsExp = JqId("targetdiv") ~> JqAppend(newLi)
"#mySubmitButton" #> SHtml.ajaxButton("Go", () => appendJs.cmd)
}
You'll also have to adapt the HTML a little, like using a normal <button> with id="mySubmitButton".

Scala JavaScript Routing Play Framework

I'm using Play framework with Scala. I'm facing a weird error and can't figure out what's the solution. The error message is:
value Track is not a member of object controllers.routes.javascript
<script type="text/javascript" src="#routes.TrackController.javascriptRoutes"></script>
#helper.javascriptRouter("jsRoutes")(
routes.javascript.Track
)
def Track(id:Long)= Action {implicit request =>
Ok(views.html.track(
new TrackData(TrackClient.getTrack(id))))
}
def javascriptRoutes = Action { implicit request =>
Ok(
Routes.javascriptRouter("jsRoutes") (routes.javascript.TrackController.Track)).as("text/javascript")
}
#JavaScriptRouting
GET /track/:id #controllers.TrackController.Track(id: Long)
GET /javascriptRoutes #controllers.TrackController.javascriptRoutes
The new error is :
1#(message: String)
2
3#main("Welcome to Play 2.1") {
4
5 #play20.welcome(message)
6
7}
index.scala.html at line 3. Cannot find any HTTP Request Header here
It says index.scala but I have never changed it.
Your javascript route is defined as:
GET /javascriptRoutes controllers.TrackController.javascriptRoutes
Edit: play uses a special reverse route for javascript, under routes.javascript.
so your reverse controller will be at controllers.routes.javascript.TrackController.Track:
#helper.javascriptRouter("jsRoutes")(
routes.javascript.TrackController.Track
)
You also need to make an implicit RequestHeader available in your template. So add at the beginning of your template:
#(implicit request: RequestHeader)
Or if you already have template parameters:
#(<your parameters>)(implicit request: RequestHeader)
And make sure it is available in your controller's Action:
def myController = Action { implicit request => // <-- request is a RequestHeader
// ...
Ok(views.html.myView)
}
If that view (let's call it main) is called from within another view (let's say index), then index also needs an implicit RequestHeader parameter as well, to be able to pass it down to main.
Because your controller's name is TrackController, so try to change this code:
#helper.javascriptRouter("jsRoutes")(
routes.javascript.Track
)
with this:
#helper.javascriptRouter("jsRoutes")(
routes.javascript.TrackController.Track
)

Change language of text in template in play framework 2.1.1

I want the user of the application can change the language in my play2 (play 2.1.1, scala 2.10.1) web application. I use #Messages.get(...) in my templates for i18n.
I have
application.langs="en,ru"
in application.conf. I pass "en" or "ru" to that method:
def index = Action {
Ok(views.html.index())
}
def changeLanguage(lang:String) = Action {
implicit request =>
Logger.logger.debug("Change user lang to : " + lang)
val referrer = request.headers.get(REFERER).getOrElse(HOME_URL)
Redirect(referrer).withLang(Lang(lang))
}
routes:
GET / controllers.Application.index
GET /index controllers.Application.changeLanguage(lang ?= "ru")
the template bunch (views.html.index):
#()(implicit l: Lang)
#import play.i18n.Messages
...
<a href="/about">#Messages.get("about")</li>
...
...
After redirecting the page, I see it on the same language. :(
I was read many old answers: implicit language parameter in my template does not work, redirect or action with withLang(...) method call too. Did not have a good solution so long time?
I made it work, so there are my changes. In app code (without an request instance play does not know where to get the cookie with the language?):
def index = Action {
implicit request=>
Ok(views.html.index())
}
And in the template (play.api.i18n imports automatically):
#()(implicit l: Lang)
...
<a href="/about">#Messages("about")</li>
...
...
I had the same issue and added my own message-resolution class over the play.i18n one.
For message resolution, you can have a example here (in Java): https://github.com/adericbourg/proto-poll/blob/dev/app/util/user/message/Messages.java#L76
And my controller changeLang's method calls this: https://github.com/adericbourg/proto-poll/blob/dev/app/util/security/CurrentUser.java#L71
It do not believe it is a good solution (it requires more code and I'm a lazy guy) but it works. Hope this can help...