I've worked around with Play Framework for a while but I'm almost new to Scala Templates
. For me as a C-familiar language developer sometimes it looks a bit strange
I was wondering if someone here could help me understand this code better I took it from
http://www.playframework.com/documentation/2.2.x/JavaGuide3
(Zentask Example)
#(projects: List[Project], todoTasks: List[Task])
#main("Welcome to Play") {
<header>
<hgroup>
<h1>Dashboard</h1>
<h2>Tasks over all projects</h2>
</hgroup>
</header>
<article class="tasks">
#todoTasks.groupBy(_.project).map {
case (project, tasks) => {
<div class="folder" data-folder-id="#project.id">
<header>
<h3>#project.name</h3>
</header>
<ul class="list">
#tasks.map { task =>
<li data-task-id="#task.id">
<h4>#task.title</h4>
#if(task.dueDate != null) {
<time datetime="#task.dueDate">
#task.dueDate.format("MMM dd yyyy")</time>
}
#if(task.assignedTo != null && task.assignedTo.email != null) {
<span class="assignedTo">#task.assignedTo.email</span>
}
</li>
}
</ul>
</div>
}
}
</article>
}
This 3 lines are really confusing for me :
#todoTasks.groupBy(_.project).map {
case (project, tasks) => {
#tasks.map { task =>
I do appreciate if anyone can explain me in more details what exactly these 3 lines are doing?
Thanks guys
Okay, so there are several transformations going on here.
#todoTasks.groupBy(_.project) says that a todoTask has a field called project, and we should transform that list of todoTasks into a Map where the project is the key and the values are all todoTasks that match the key.
.map { case (project, tasks) => { says that we now have a Map where the key is project and the value is a list of tasks. And if we have those two items (project, tasks), then we should do something with each task, the something is to what follows the =>
tip, you don't need to have a deep knowledge of scala to be productive as a java play developer, just do your transformations of the data in your java controller.
I don't think these are specific to Play templates at all, but rather examples of idiomatic functional Scala. The middle line uses pattern matching with an anonymous function, which is covered very nicely by this tutorial. The other two are calling functions on collections that take functions themselves as parameters. These are called "higher order functions" and are one of the key tools of functional programming. .map, in particular, is key to FP. Daniel Spiewak's Scala Collections For The Easily Bored series is a great place to get started on functions such as these.
Related
im having another rather simple issue with using cloneNode. I'm trying to duplicate a li node back into its own ul using java and I can't seem to find why its not working.
I have tried multiple things but I cant for the life of me figure it out.
I want this:
<ul id="mylist">
<li><h3>My Image:<img src="myImage.png"></h3></li>
</ul>
To look like this:
<ul id="mylist">
<li><h3>My Image:<img src="myImage.png"></h3></li>
<li><h3>My Image:<img src="myImage.png"></h3></li>
</ul>
I am using this function:
function myFunction(){
parent=document.getElementById("myList");
child=parent.getElementbyTagName("li")[0];
clone= child.cloneNode(true);
parent.insertBefore(clone,child);
}
</script>
Unsure as to why its not working, I pulled the code almost identically from an online source. If someone could help with my newbie question I would very much appreciate it.
I often find when copying javascript from the inter-rent, the author has never checked his code for typing errors or maybe they're deliberate to encourage a bit of understanding.
This works:
<ul id="myawesomelist">
<li id="x"><h3>My awesome image:<img src="myawesomeimage.png"></h3></li>
</ul>
and here's the javascript:
function myawesomefunction()
{
var myawesomeparent=document.getElementById('myawesomelist');
var myawesomechild=myawesomeparent.getElementsByTagName('li')[0];
var myawesomeclone=myawesomechild.cloneNode(true);
myawesomeparent.insertBefore(myawesomeclone,myawesomechild);
}
And here's the fiddle I built it in:
http://jsfiddle.net/g51n8sor/
I'm using Grails 2.3.5 and try to persist multiple domains coming from a dynamic form.
To achieve this, I used the approach with lazy lists like described in: http://omarello.com/2010/08/grails-one-to-many-dynamic-forms/
The forms are genereated well and all the neccessary parameters are in the params-map,
but the binding to the list does not work.
I read a lot about this topic the last two days and found good answers on stackoverflow,
but I think these methods only work for older grails versions.
To illustrate my problem, some code:
House.groovy
class House {
....attributes removed to minimize example
List<Adress> adresses = [].withLazyDefault { new Adress() }
// List adresses = ListUtils.lazyList(new ArrayList<Adress>,FactoryUtils.instantiateFactory(Adress.class));
static hasMany = [adresses:Adress]
//def getAdresses(){
//return LazyList.decorate(adresses, FactoryUtils.instantiateFactory(Adress.class))
//}
static mapping = {
adresses cascade:"all-delete-orphan"
}
Template for dynamic forms --> Are created correctly
<div id="adress${i}" class="adresses-div" style="<g:if test="${hidden}">display:none;</g:if>margin-bottom:10px; ">
<g:hiddenField name='adresses[${i}].id' value='${adresses?.id}'/>
<g:hiddenField name='adresses[${i}].deleted' value='false'/>
<g:hiddenField name='adresses[${i}].neu' value="${adresses?.id == null?'true':'false'}"/>
<g:textField name='adresses[${i}].street' value='${adresses?.street}' />
<g:textField name='adresses[${i}].land' value='${adresses?.land}' />
<span class="del-adresses">
<img src="${resource(dir:'images/skin', file:'database_delete.png')}"
style="vertical-align:middle;"/>
</span>
HouseController - edit action
houseInstance.properties = params
So, the form templates are created correctly and the the input values are existent in the parameter map.
My problem is now the databinding for multiple adresses created from one form.
According to the example project provided by the link above, the parameter binding should automatically create new Adress-Objects and save them as childs for a house.
When debugging my application I can see that there are the right parameters but it seems that the list cannot create a new Adress-Object.
The 'adresses' list, contains a null value after binding--> [null]
Like mentioned above, I tried a few solutions for this problem, but couldn't resolve it.
Probably the lazylist approach is not supported in grails 2.3.5 and only works for older version.
I hope someone had the same same problem and can give me a hint
Thanks in advance
I have experience with the same problem.
Refer to this: grails 2.3 one-to-many databinding with dynamic forms
Try to remove id: in params if it's a new phone. Tested with grails 2.3.11 and using it in my project.
Here is what I changed in _phone.gsp
<div id="phone${i}" class="phone-div" <g:if test="${hidden}">style="display:none;"</g:if>>
<g:if test="${phone?.id != null}">
<g:hiddenField name='phones[${i}].id' value='${phone?.id}'/>
</g:if>
...
</div>
Thanks to #hakuna1811
After carefully reading the docs for grails 2.3.x, I saw how the parameter map should look like with multiple child-domains.
Example:
def bindingMap = [name: 'Skyscraper',
'addresses[0]': [street: 'FirstStreet'],
'addresses[1]': [street: 'SecondStreet']]
But my map looked like this:
def bindingMap = [name: 'Skyscraper',
'addresses[0]': [street: 'FirstStreet', 'SecondStreet']]
I have never noticed this before...
The problem was the jQuery code to clone all the necessary input fields and update
the corresponding ids. By removing this code and testing my application with two static address fields I got it to work.
<g:textField name="adresses[0].street" value=""/>
<g:textField name="adresses[0].zip" value=""/>
<g:textField name="adresses[1].street" value=""/>
<g:textField name="adresses[1].zip" value=""/>
As a short-term solution I decided to create predefined hidden forms. When clicking on the add-Button some simple jQuery will show one form...
The next couple of days I will review my code to get really dynamic behaviour. If I have results, I will add them to the topic here.
I am trying to add an htmlview (which is using declarative support according to SAP's docs) to an index page that is also using declarative support. Using data-sap-ui-type="ui.MyView" makes me to ask two questions:
Is there any equivalent to sap.ui.localResources in declarative support?
data-ui-type is not adding the view.html suffix to the view that should be laoded. Is there a special pattern for MVC in declarative support or is there currently no way to implement it?
Kind regards,
Nico
find some basic samples here:
https://openui5.hana.ondemand.com/#docs/guide/MVC.html
First of all I believe that you always have to set sap.ui.localResources in code.
As you can see instanciating a HTMLView from an HTMLView goes like this:
<div data-sap-ui-type="sap.ui.core.mvc.HTMLView" id="MyHTMLView" data-view-name="example.mvc.test2"></div>
This will load example.mvc.test2.view.html and place it into your parent view.
Generally speaking the JS API translates into HTMLViews like this:
new sap.ui.AnyControl("myId", {
aLittleProperty: "10",
property: false,
press: functionInMyController,
morePress: a.static.myFunction,
defaultAggregation: [
new sap.ui.OtherControl("otherId1"),
new sap.ui.OtherControl("otherId2")
],
anotherAggregation: new sap.ui.OtherControl("otherId3")
}).addStyleClass("myClass");
<div data-sap-ui-type="sap.ui.AnyControl"
id="myId"
class="myClass"
data-a-little-property="10",
data-property="false"
data-press="functionInMyController"
data-more-press="a.static.myFunction">
<div data-sap-ui-type="sap.ui.OtherControl" id="otherId1"></div>
<div data-sap-ui-type="sap.ui.OtherControl" id="otherId2"></div>
<div data-sap-ui-aggregation="anotherAggregation">
<div data-sap-ui-type="sap.ui.OtherControl" id="otherId3"></div>
</div>
</div>
Note that:
The id and CSS classes are set with the regular HTML attributes
Property names translate from camelCase to lower-case separated with "-" (due to the fact that HTML is not case-sensitive)
No matter what type the property is you of course have to put it in quotes in HTML
Whatever you put directly inside a HTML-defined control is considered to belong into it's default aggregation
BR
Chris
Why use scala template-engine in playframework 2 (scala) if we may stay with just scala.
Using template engine is:
additional processor time transforming template syntax into scala code
then compiling this code (which is not so concise as it if write it by hand - then it compiles even slower)
Also if template is not converted yet into scala you can see that code inconsistency (red highlighting in your IDE) from you main code -
so you should every time think about it..
Why not just use core xml/html support what scala provides like here: http://www.scala-lang.org/node/131
Is there any pure scala template (you can recommend) I can use in play-framework or alone ?
Actually you should ask this question to the dev team, however consider few points:
Actually you don't need to use the Play's templating engine at all, you can easily return any string with Ok() method, so according to your link you can just do something like Ok(theDate("John Doe").toString())
Play uses approach which is very typical for other MVC web-frameworks, where views are HTML based files, because... it's web dedicated framework. I can't see nothing wrong about this, sometimes I'm working with other languages/frameworks and can see that only difference in views between them is just a language-specific syntax, that's the goal!
Don't also forget, that Play is bilingual system, someone could ask 'why don't use some Java lib for processing the views?'
The built-in Scala XML literals are not well-suited for creating complex programs, you easily run into issues (that's also why there's a library called anti-xml); Martin Odersky himself regretted making this a language feature
Finally, there are IDEs with support for Play 2 views, I'm working on Idea 12 with Play2 support and although it's not perfect (it's quite new, so sometimes there are small problems) in most cases it works fine. It understands Play view's syntax, offers autocomplete, even you can use option+click on some object in the view to jump directly to the method/model's declaration, etc.
Answering to your last question, AFAIK officially there is Groovy engine available as a module, which offers template engine known from Play 1.x, however, keep in mind it's just a bridge for people migrating from Play 1.x to Play 2.x as it's just slower than native engine of Play 2.
For me this fits
as an answer, for last question at least.
This just scala. Just XML built-in magic.
http://www.alvarocarrasco.com/2011/03/play-framework-and-templating-with.html?m=1
Sample:
This is a template: Templates.scala file
package templates
import play.api.templates.Html
import scala.xml.Xhtml
import controllers.routes
object Main {
def page (title:String="Default title")(content: => scala.xml.Elem) = Html {
"<!DOCTYPE html>" +
Xhtml.toXhtml(
<html>
<head>
<title>{title}</title>
<link rel="stylesheet" media="screen" href={routes.Assets.at("stylesheets/main.css").toString()} />
<link rel="shortcut icon" type="image/png" href={routes.Assets.at("images/favicon.png").toString()} />
<script src={routes.Assets.at("javascripts/jquery-1.9.0.min.js").toString()} type="text/javascript" />
</head>
<body>
{content}
</body>
</html>
)
}
// a panel template, just as an example
def panel (label:String="Some label")(content: => scala.xml.Elem) = {
<div class="panel">
<div class="panel-label">{label}</div>
<div>{content}</div>
</div>
}
}
This is an index page index.scala file
package views
import templates.Main._
object IndexPage {
def apply() = {
page(title="Welcome to my Page!") {
<div>
<h1>Hello</h1>
<p>Some template markup</p>
{
panel(label="Dashboard panel")(
<div>
Panel content
</div>
)
}
</div>
}
}
}
This is a controller: Application.scala file
package controllers
import play.api.mvc._
object Application extends Controller {
def index = Action {
Ok(
views.IndexPage()
);
}
}
I'm a beginner about Razor, and sometimes I get stuck with really simple things.
I have this foreach loop:
#foreach (dynamic item in ViewBag.EAList)
{
<li>
#using (#Html.BeginForm("Duplicate, "Daily"))
{
<p>#item.AuthorComment</p>
#Html.Hidden("EstadoDeAlmaID", #item.EAID)
#Html.Hidden("PosterID", Session["id"].ToString())
<input type="submit" value="Send" />
}
</li>
}
This line:
#Html.Hidden("EstadoDeAlmaID", #item.EAID)
Doesn't work, and I don't know how to make it work, I tried many ways, without #, with (--), with #(--)...
Could someone help me to display the dynamic value in my hidden field?
In addition, if someone know about a good Razor samples websites, I would be very thankful.
I had the same problem, found that a simple cast solved my problem.
#Html.Hidden("id", (string) ViewBag.ebook.isbn)
In Razor, once you are in "C# land", you no longer need to prefix values with # sign.
This should suffice:
#Html.Hidden("EstadoDeAlmaID", item.EAID)
Check out Scott Gu's article covering the syntax for more help.
Update
And I would also move your <li></li> within your using block, as Razor works better when you wrap HTML blocks inside of a code blocks.
Also, your Html.BeginForm should live outside of your loop.
#using (#Html.BeginForm("Duplicate, "Daily"))
{
<ul>
#foreach (? item in ViewBag.EAList)
{
<li>
<p>#item.AuthorComment</p>
#Html.Hidden("EstadoDeAlmaID", item.EAID)
#Html.Hidden("PosterID", Session["id"].ToString())
<input type="submit" value="Send" />
</li>
}
</ul>
}
Where ? in the foreach loop is the type of your items in EAList.
To avoid the Extension methods cannot be dynamically dispatched exception, use a model instead of ViewBag so you will not be using dynamic objects (this will avoid all the unnecessary casting in the View and is more in line with MVC style in general):
In your action when you return the view:
return View("ViewName", db.EAList.ToList());
In your view, the first line should be:
#model IEnumerable<EAListItem> //or whatever the type name is
Then just do:
#foreach(var item in Model)
You got the error, "Extension methods cannot be dynamically dispatched"... therein lies your trouble.
You should declare you loop variable not to be of type dynamic, but of the actual type in the collection. Then remove the # from the item.EAID call inside the #Html.Hidden() call.
The simple solution for me was to use ViewData instead of ViewBag. ViewBag is just a dynamic wrapper around ViewData anyway.
#Html.Hidden("ReportID", ViewData["ReportID"])
but I don't know if this will help in your case or not since you are creating dynamic items in your foreach loop.
I have found that when i want to use the view bag data in the HTML
Getting back to basics has often worked for me
<input type="hidden" name="Data" id="Data" value="#ViewBag.Data" />
this gave the same result.