Generate dynamic HTML file - scala

I am new to Scala. I have predefined html file. I want to plug dynamic content in HTML file.
e.g.
$for(products in product)
<div>product.name</div>
<div>product.description</div>
Here products is Scala collection. I can load html file and feed dynamic values(products).
Would you advise me how to do this in Scala?

Twirl templates
compiled, typesafe, composable, scala inside Html tags (akin angular js [javscript inside Html])
Twirl templates enable you to write scala inside a html, its typesafe, gets compiled to functions and are composable as well.
orders.scala.html
#(customer: Customer, orders: List[Order])
<h1>Welcome #customer.name!</h1>
<ul>
#for(order <- orders) {
<li>#order.title</li>
}
</ul>
Without any library
Scala has good support for string interpolation and also provides triple quote syntax for declaring strings with espace characters which is very handy. You can produce dynamic Html using this simple method
case class Product(name: String)
case class Html(content: String)
def produceHtml(products: List[Product]): Html = {
Html {
products.map { product =>
s"""
|<div> ${product.name} </div>
""".stripMargin
}.mkString("\n")
}
}

Related

Play Framework 2.4.0 and I18n with Scala

I have a project with Play Framework 2.3.8 and I'm migrating in Play Framework 2.4 but I have a problem with I18n.
Now I have in a view code like this:
#Messages("components.navbar.text")(locale.MyLang)
where locale is:
object locale {
var MyLang =Lang("it")
def changeLang(newLang:String): Unit ={
MyLang=Lang(newLang)
}
}
I would mantainer this structure without using implicit lang, is possible ?
I have some situation where I use in the same page different language and in this case is difficult and boring with the implicit lang.
If I understand your question correctly, which is that you want to override the user's chosen language for certain blocks of the page, I would do this (for Play 2.4) using an implicit Messages object:
#()(implicit messages: Messages)
<!-- some section in the user's chosen language -->
<h1>#Messages("hello.world")</h1>
<!-- some section in a specific language -->
#defining(messages.copy(lang = play.api.i18n.Lang("it")) { implicit messages =>
<h2>#Messages("something.in.italian")</h2>
}
That is, use defining to create a new (implicit) messages for certain nested blocks of HTML.
If you really wanted to go to town (and I wouldn't necessarily recommend this) you could add an italian method to Messages via an implicit class:
(in my.package.utils.i18n.MessagesExtensions.scala):
package my.packages.utils.i18n
import play.api.i18n.{Lang, Messages}
implicit class MessagesExtensions(messages: Messages) {
def italian = messages.copy(lang = Lang("it"))
// and an `as` method for good measure:
def as(code: String) = messages.copy(lang = Lang(code))
}
To have that work in a view you need to add the class to your templateImport in your build.sbt:
templateImports in Compile ++= Seq(
"my.packages.utils.i18n.MessagesExtensions"
)
Then in your templates you can just to this:
#()(implicit messages: Messages)
<!-- some section in the user's chosen language -->
<h1>#Messages("hello.world")</h1>
<!-- some section in a specific language -->
#defining(messages.italian) { implicit messages =>
<h2>#Messages("something.in.italian")</h2>
....
}
<!-- or singly, in another language -->
<h3>#Messages("another.thing.in.french")(messages.as("fr"))</h3>
But that might be overkill, unless it really saves you a lot of boilerplate language switching.

Play framework dynamic template include

I have a template that has to include another template based on the file name that comes from the database. For example, here is a template that takes a String that contains the name of the template file that will be included in another template.
#(sourceCodeFileName: Option[String])
#{sourceCodeFileName match {
case Some(sourceCode) => {
#sourcecode.sourceCodeFileName + "scala.html"
}
}}
Where sourcecode is the package where the actual template resides. For example., if the String parameter to the above template is given as myview, then I want to include myview.scala.html. Is there a way to do this in Play framework?
To inject HTML from a static file to a scala template, you can define a function in your template:
#import scala.io.Source
#injectHtmlFromFile(sourceCodeFilename: String) = { #{
Html(Source.fromFile("static/html/" + sourceCodeFilename + ".html").mkString)
}}
…and call it later in the template this way:
#injectHtmlFromFile(sourceCode.sourceCodeFileName)
Side note
I'm not sure I quite understand the question – I've answered the OP's comment and the same question posted by him on Google Groups.
A Play scala template is a function returning Html. You should obtain the template object in the controller and pass it to the template. But in simple cases it's just easier to pass the rendered Html:
Your template would then look like this:
#(content: Option[Html])
#content
and the controller:
object Application extends Controller {
def index = Action {
val sourceCodeFileName= ...
Ok(Some(Class.forName("views.html."+sourceCodeFileName)
.getConstructor().newInstance().asInstanceOf[() => play.api.templates.Html]()
))
}
}

Form errors i18n Play framework

I'm using the form helper and a custom form template to render my forms in the Play framework like this:
#(lang: Lang)(myForm: Form[MyModel])
#import play.i18n._
#import helper._
#implicitField = #{ FieldConstructor(formTemplate.f) }
#form ( action = routes.Application.index() ){
#inputText(
field = myForm("username"),
'_label -> Messages.get(lang, "username")
)
}
When the template is called with different values for lang, the label is displayed in the respective language.
However, when the form is submitted, error messages are always displayed in the main language. (i.e. for Required fields it's always This field is required.)
As the answer to this post mentioned, I changed the default error messages like so in my language files (currently only 2):
messages.en:
username=Username
error.required=This field is required
messages.nl:
username=Gebruikersnaam
error.required=Dit veld is verplicht
How can I make sure the errors are printed in the correct language?
I've already tried doing the following in my custom template, but without success:
#(elements: helper.FieldElements)
<!-- snipped some HTML code -->
<span class="help">
#(elements.infos(elements.args.get('_lang) match {
case Some(language) => language.asInstanceOf[play.api.i18n.Lang]
case None => new Lang("en","uk")
}).mkString(", "))
</span>
And by adding '_lang -> lang to my #inputText call.
I'm used to programming in Java and have only done some Scala in the Play templates. I'm using Play 2.0.4.
I have found the easiest way of doing this (note: I program in Java) is by defining a static method in one of your models that returns the users language:
public class User{
import play.i18n.Lang;
//simplified
public static Lang getLanguage(){
if(session("language" != null){
return Lang.forCode(session.get("language"));
} else {
return Lang.forCode("en"); //default language
}
}
You can then call this static function in your Scala form template like this:
<span class="errors">#elements.errors(User.getLanguage()).mkString(", ")</span>
to display translated errors based on the default error messages in your messages.xx files.
As a general matter, if your error codes are also found in the messages.xx resource files, they get localized, even if you program a custom validator somewhere else. You don't have to have the Lang in scope or call Messages() yourself. E.g. in Scala Play:
val validPhone = """\+?[0-9_\-\. \(\)]*$""".r
val phoneCheckConstraint: Constraint[String] = Constraint("constraints.phonecheck")({
plainText =>
val errors = plainText match {
case validPhone() => Nil
case _ => Seq(ValidationError("error.phonenumber"))
}
if (errors.isEmpty) {
Valid
} else {
Invalid(errors)
}
})
If you merely have
error.phonenumber=Invalid phone number
in your messages.en file and translated versions in other messages.xx files they will get localized by Play even though no Lang was in scope at the point of declaration. So no need to pass Lang around other than in your templates and elsewhere for explicit Messages() calls.

Scala Lift - Dynamic page chrome

I have a page which is passed an id from which the content is determined. What I'm looking to do is dynamically replace the pages "chrome" depending on the content.
So if I have a db record "Book", I'd like to display the Book chrome in templates-hidden.
Thanks for any help, much appreciated :)
You can define a snippet that selects the template you want and pass the xhtml NodeSeq containing the template selection to it:
<lift:TemplateSnippet.dynamicTemplatePicking>
<lift:surround dynamic:template="" at="content">
<h2>some heading</h2>
<p>some text</p>
</lift:surround>
</lift:TemplateSnippet.dynamicTemplatePicking>
And the snippet code:
class TemplateSnippet {
def dynamicTemplatePicking(xhtml :NodeSeq) :NodeSeq = {
bind("dynamic", xhtml, AttrBindParam("template", Text("default"), "with"))
}
}
By changing the "default" in Text("default") inside the snippet you can choose another template depending on your needs. Maybee you want to do something like def choose (record: Record) = record match { case b: Book => "booktemplate"} and so on...
Source: Mads Hartmann's posting

How to make a snippet in Lift - Scala

What I need to do is to put one tag into html page:
<lift:surround with="default" at="content">
<span class="lift:WorkingStatus.print"></span>
</lift:surround>
and to have a snippet class in appropriate snippet.* package:
class WorkingStatus {
def print():String={return "<table></table>";}
def speak = <span>Hello World</span>
def render = "* *" #> "Hello there in span"
}
function will generate some html table in string which will show up in html, like in def print() .
So, this is something rather trivial I cannot get to work in any way. I need a Scala class which could be incorporated wherever needed in html pages, like - lets say - with <jsp:include> and this class should be able to connect to outer web service, get list of some data and generate html which will then be inserted on desired places... complicated enough? :)
You have a wrong signature for the print method. Snippets' methods are NodeSeq => NodeSeq.
So the more verbose variant is
def print(xhtml:NodeSeq):NodeSeq={return <table></table>;} or you can use
def print = "*" #> <table></table>
if you will need a some kind of transformation, or just:
def print = <table></table>