playframework with Twirl views not found: value - scala

i pass a lot of time trying to solve very simple problem render à string or(List) from controller to view using playframework java and Twirl, my code here
in my controller
public Result list(){
//List<String> todo = Arrays.asList("sup1","sup2","sup3");
String nana = "coco";
return ok(index.render(nana));
}
in my view
#(message: String)
#(nana:String)
#main("Welcome to Play") {
#play20.welcome(message, style = "Java")
<h1>#nana</h1>
}
so there are the some configuration for Twirl or automatically ? anyone help me to render data to view and thanks

What is the error you're seeing? What are the full blocks of code, with all imports?
The syntax seems to be all wrong:
Your template should only have one parameter declaration, which is the #(...) line at the top. If you want to pass in two values, you should write #(message: String, nana: String) at the top of your template. And then you need to pass values for both in when you call index.render(message, nana).
I'm not sure what #main refers to, since imports aren't listed, but you should try getting it to work first without that block. Render a plain string, then add in some variables, then maybe try for a fancy callback like #main.

Related

Pass data to a ScalaFX JFXApp

I wrote a GUI in ScalaFX whichs works quite well when testing it isolated. Things to mention:
The "real" application itself already has a main method, and only that one should be used to start the application, not the one I get when extending JFXApp. So the call to the main method of JFXApp is done manually, from the outside
It should be possible to pass a data structure to the JFXApp, so I added a setter
The whole startup procedure looks like this:
def main(args: Array[String]) {
...
...
JFXGui.setData(data)
JFXGui.main(Array())
}
The problem:
I cannot draw the contents of the data object as long as the main method of the JFX object is not called, so setData is really just a simple setter method. The idea is that JFXGui should draw the data as soon as possible after JFXGui.main was called. But: how can I realize this inside of JFXGui? Is there something like an "onready"-method?
In the above code, I tried to put the call to the setter after the call to the main method, so that the setter can trigger the drawing. What I hadn't in mind is that JFXGui.main is blocking forever, therefore the call to the setter is unreachable code.
How could I fix this? any help is appreciated, thanks.
edit:
JFXGui is the name of my ScalaFX UI:
object JFXGui extends JFXApp {
private var data: Data = _
def setData(data: Data) {
this.data = data;
}
// tons of ScalaFX related things which visualize the data object
// ...
}
Solution 1 (reusing JFXApp)
The Gui object no longer should be an object, but a class with constructor parameters.
class Gui(data: Data) extends JFXApp {
//your existing code without the field data and the method setData()
}
In the startup class:
new Gui(data).main(Array())
Solution 2 (Custom init)
You do not necessarily have to use JFXApp in order to run your application. I suggest you having a look at the source code of JFXApp.main() and the class AppHelper. They contain ~10 lines of code combined so you can just copy their source code and tailor it to your needs.

How to serve a Play! scala template without routing through controller?

I want to have something like
Routes
GET /endpoint pathToTemplate.templateName.scala.html
In order to avoid the need to create a controller just to serve this template.
I need a template because I am serving up values using an imported scala library so this can't just be static html
#import tool.values._
<p>
#Tool.getValue()
<p>
It is impossible to achieve your desire solution but you can to make a workaround with one controller and the dynamic URL parts mapping.
Firstly create a controller which serves a view for any provided path. Route definitions must be placed in code for example with usage of a simple hash map instead of the route file.
object GlobalController extends Controller {
private val getRouterMap = Map(
"view1" -> views.html.view1(),
"view2" -> views.html.view2(),
"sub/view3" -> views.html.view3()
)
def route(path: String) = Action { implicit request =>
Ok(getRouterMap.getOrElse(path, views.html.notFound()))
}
}
Secondly at the end of the route file define a mapping for the created action as follow.
GET /*path controllers.GlobalController.route(path)
It is very important to put it as the last line. Otherwise it will shadow all other mappings defined below.
Hint
Anyway if I ware you I would reconsider your design. Singleton objects aren't easily testable. Sooner or later they will make your life really painful.

PlayFramework instantiate object in current request scope?

I am currently active PlayFramework learner who came from world of PHP.
For example I have a Head block object in my app, which should hold title, charset encoding, meta information, etc. Something similar to Magento blocks, but without XML declaration
package blocks.Page
object Head {
var title: String = "";
}
In Application.index() method I have
blocks.Page.Head.title
Ok(views.html.application.index());
And finally in html template
#import blocks.Page.Head
<title>#Head.title</title>
However, blocks.Page.Head object is defined for entire application scope, not for single request. This object is the same for each request.
What is the right way to do, what I am trying to do? I can create container with all blocks and instantiate it with each request, then just pass to all templates. But I have a feeling that this is wrong way.
Just use usual class instead of object and pass instance to template as parameter.
Like this:
package blocks.Page
case class Head(title: String = "")
Controller:
val head = Head("Blah")
Ok(views.html.application.index(head))
And template will looks like:
#(head: blocks.Page.Head)
...
<title>#head.title</title>
I know the feeling when coming from a request-oriented language like PHP :). However, consider application-wide access as a gift of a VM (in PHP we need to go the extra mile of using some bytecode and data caching tool like APC or eAccellerator).
I would probably create a blockManager class which gives you static access to blocks by name/tag/id from the template: Block.get("MyBlock"). Then you can define and later modify your caching / storing strategy (holding in memory vs. loading from storage) without affecting your templates.

How to pass optional parameter to scala template in play framework 2

Is it possible for the java controller in playframework 2 to pass optional parameter to the scala page?
I have a scala page which I'm rendering from different actions. only in a certain case one of these actions is supposed to pass a parameter to the scala, do i have to change every render call? basically i want to call template.scala.html
in 2 ways
template.render(msg) //java
and
template.render()//java
where in my template i have this:
#(msg:String = "xyz")
currently i get an error for call with no message that it doesn't
render(java.lang.String) in views.html.template cannot be applied to ()
As a work-around you could store your parameter in the Context.args map. It's a Map<String,Object> so you can store anything that's needed for the current request.
That's an easy way of making values accessible in your templates without having to declare/pass them as parameters.
Controller
public static Result someAction()
{
ctx().args.put("msg", "Hello world!");
return ok(myview.render());
}
template
#if(ctx.args.containsKey("msg")){
<p>#ctx.args.get("msg")</p>
}
In Play Framework 2 for Java the controller have to pass a default value or null.
In other templates you can leave the optional parameter away.

Play-Scala: How to use method overloading In actions?

I want to make tow action with different Input and make one able to call the other:
def showQuestion(questionId :Long)=Action{
Redirect(routes.Application.showQuestion(Question.find.byId(questionId)))
}
def showQuestion(question :Question)=Action{
Ok(views.html.show(question))
}
I tried the above but no luck. the compiler complaining:
found : models.Question
[error] required: Long
[error] Redirect(routes.Application.showQuestion(Question.find.byId(questionId)))
referring to first one.
I think that you are missing something.
In your routes file, you can't map an Url to the second Action:
GET /question/:id controllers.Question.showQuestion(id: Long)
GET /question/:question controllers.Question.showQuestion(question: Question) // <== how to map the "question" in the Url ???
So why not something like that (in this case, it is not really relevant to use two methods) :
def showQuestion(questionId: Long)=Action{
showQuestion(Question.find.byId(questionId))
}
private def showQuestion(question: Question)=Action{
Ok(views.html.show(question))
}
It's not a direct answer, however there's some point worth of thinking:
Main task for the router is translation and type-validation of params from request to function's args, so it's definitely better use some common types such as String, Int, Bool etc, to identify the objects in DB instead trying to pass whole objects through the router. Actually your first route does that properly.
I can't find any good reason for using two separate actions for finding the object and rendering the template (with object found in other action). What's more, you are trying to do that by Redirect, so it creates two requests, it's redundant! You should just delete second route and use one action:
GET /question/:id controllers.Question.showQuestion(id: Long)
def showQuestion(questionId: Long)=Action{
Ok(views.html.show(Question.find.byId(questionId)))
}
If you really, really want to split it to two separate functions, use sample of #nico_ekito, I think that you can delete second route in such case as well.
If in future you will want to overload function... better don't do it :) Overloading is fine, when you have static method available for usage in many places and it can differ with numer of arguments etc. Most probably it will be just more comfortable to work with different names of actions (even if routes will be similar) :
GET /question/:id controllers.Question.showById(id: Long)
GET /question/:name controllers.Question.showByName(name: String)
// so finally in the view you can use it just as:
<a href='#routes.Question.showById(item.id)' ...
<a href='#routes.Question.showByName(item.name)' ...