Creating a custom field constructor in Play 2 (scala) - scala

I am trying to grok the instructions given in the play 2 scala tutorial for form template helpers. I am getting stuck in the section "Writing your own field constructors". It gives a sample template (without saying what the name of the file should be):
#(elements: helper.FieldElements)
<div class="#if(elements.hasErrors) {error}">
<label for="#elements.id">#elements.label</label>
<div class="input">
#elements.input
<span class="errors">#elements.errors.mkString(", ")</span>
<span class="help">#elements.infos.mkString(", ")</span>
</div>
</div>
Then it shows this code:
object MyHelpers {
implicit val myFields = FieldConstructor(myFieldConstructorTemplate.f)
}
I am confused about how this is supposed to relate to the template. (eg, is the template file supposed to be called myFieldConstructorTemplate.scala.html?) I tried some variations on this without luck.
I'm new to both scala and Play, but I also know play 2 and its docs are new, so I'm not sure what incredibly obvious thing I'm missing.
thanks!

I've just had the same problem, I agree with you the documentation is not clear at all...
Possible error 1
not found: value FieldConstructor
It means that you haven't imported the helper with this instruction :
#import helper._
Possible error 2
not found: value implicitConstructor
It means that you are declaring the field constructor in the wrong place in your template (i.e. : in the #helper.form method). To fix this, I declared my field constructor just after my import instructions :
#import form._
#import helper._
#implicitConstructor = #{ FieldConstructor(foundation_field.render) }
(My foundation_field.scala.html file is in the views.form package).

In the tutorial this code is along the text:
Often you will need to write your own field constructor. Start by
writing a template like:
This means you have to create your own template (xxxx.scala.html) and add that code inside. After that, you import it in your template with the code they provide (remember to add that to each scala template that uses your custom field):
#implicitField = #{ FieldConstructor(xxxx.f) }
Check the samples of Play, the Forms sample uses a similar approach with Twitter bootstrap.

To follow the logic of Scala implicit keyword, the document is implicit too ;)
Scala and Play are too immature right now, for that reason the documentation is very poor.
This SOF answer is very good: https://stackoverflow.com/a/15268122/1163081
You can also check the Play source for more examples: https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/views/html/
Or this guys appears to discover the solution: https://groups.google.com/forum/#!msg/play-framework/2e1EqZJ-Qks/gXD1oo0IjfcJ

Related

Set class or ID on <h:inputHidden> in JSF

I'm trying to set a class or id parameter on a <h:inputHidden> in JSF. The code looks like this:
<h:inputHidden value="#{getData.name}" class="targ" />
But in the browser, the class isn't set:
<input type="hidden" name="j_idt6" value="j_idt6">
I need to set a class to this parameter, because I have a JavaScript autocomplete function for a <h:inputText> that sets a value in the hidden input, which needs to be passed in the next page.
Any ideas? Thanks!
I know it's a little bit late, but it can help someone in the future.
As inputHidden shows nothing in the browser there's no sense to allow it to have a class.
You can use the Id but as the Id could change as you change the component parents using it would bring some headache.
I'd suggest as a workaround, you can give it a parent so you can manipulate it by javascript.
Exemple:
JSF
<h:panelGroup styleClass="someCssClass">
<h:inputHidden id="someId" value="someValue" />
</h:panelGroup>
Javascript (using jQuery, you could use pure javascript also)
$('.someCssClass input[type=hidden]').val('yourNewValue');
None of these answers here satisfied my needs (need the PrimeFaces component, need class not ID, wrapping is too much work), so here's what I came up with:
Use pass-through attributes: https://www.primefaces.org/jsf-2-2-pass-through-attributes
Use pass:hidden-class="blah" (in my case, it's xmlns:pass up top)
Use [attribute=value] selector:
https://www.w3schools.com/cssref/sel_attribute_value.asp
document.querySelector multiple data-attributes in one element
That basically boils down to using something like this (because h:inputHidden becomes a regular input): document.querySelector("input[hidden-class=" + blah + "]")
Please, see similar question - How can I know the id of a JSF component so I can use in Javascript
You can sed "id" property, but in final html code it can be not the same, but composite: for example, if your input with id="myhidden" is inside form with id="myform", final input will have id="myform:myhidden".
In the end, I used a standard HTML <input type="hidden"> tag, as I had no advantages for using the JSF one. If you're trying to set a value in a hidden input with JavaScript, I recommend using this workaround.

Why bindings do not work?

<textbox id="nextTitleTextbox" readonly="true" value="#bind(ivm.inventory.successorTitleName)" />
<button id="nextTitleButton" label="..." mold="trendy" onClick="#command('chooseFormerOrSuccessor', isFormer = false)"/>
<a id="nextTitleHrefView" href="/inventory_new.do?method=edit&docUID=${ivm.inventory.successorTitleName}">view</a>
<a id="nextTitleHrefHistory" href="javascript:showRenamingHistory(${ivm.inventory.successorTitleName},${ivm.inventory.successorTitleName})">history</a>
The problem is in 'a' tags. Textbox and buttons works fine, but links in 'a' tags do not catch information from binding, so link there looks like /inventory_new.do?method=edit&docUID=. I really don't understand what's wrong here, because I tried a lot of combination and something similar is working on other pages. Where is mistake in this binding?
I even tried to put string from zscript
<zscript>
String successorTitleHref = "/inventory_new.do?method=edit&docUID=" + ivm.inventory.successorTitleName;
</zscript>
But got exception:
Typed variable declaration : Class or variable not found: ivm.inventory.replacementTitleName.
Also, it's supported controls, that locates in separate file, and every control adding with use derective.
Binding in ZK has nothing to do with variable replacement. #bind() doesn't mean you can use ${...}. The two are completely separate concepts even though both are called "EL Expression" in the manual. But binding EL Expression and ZUML EL Expressions are two different things.
To allow access to ivm in a zscript, you need to define this variable somewhere in the script. One way is to instantiate it:
IVM ivm = new IVM();
or you can use a custom variable resolver.

Play! Framework Form/HTML Helpers: Separation of Concerns?

I just started playing around with Play 2.1.1 using Scala. Going through some tutorials/sample apps, I came across the helper methods that can be used to create forms, e.g.:
#(myForm: Form[User])
#helper.form(action = routes.Application.submit) {
#helper.inputText(myForm("username"))
#helper.inputPassword(myForm("password"))
}
I am still a n00b to this. But as far as I understand, this basically requires a form object being defined within the controller, which "wraps" the model (simplified):
val loginForm = Form(
tuple(
"email" -> text,
"password" -> text
))
)
def login = Action { implicit request =>
Ok(html.login(loginForm))
}
I found this suprising, as I get the feeling that the indirection through the Form object seems "in the wrong place". What I was expecting was something like this (pseudo):
#(user: User)
#helper.form(action = routes.Application.submit) {
#helper.inputText(() => user.userName)
#helper.inputPassword(() => user.password)
}
...so that one does not have to define the Form object within the controller; all form-related stuff would be located within the view template.
Mixing the "this-will-be-rendered-into-a-form" logic into the controller seems like a minor violation of SOC to me.
Now I'm wondering: Is this just the way things are done in Play, or did I miss something? Is there a "nicer" way to handle this?
Cheers, Alex
I think it would be annoying too with many form definition in controller, especially the apps will involved many form.
But Play!Framework make developer to write code more flexible. You can mix plain HTML inside scala template helper like this :
#helper.form(action = routes.Application.submit) {
<input type="text" name="username">
<input type="password" name="password">
....
}
In my opinion, the scala helper actually helpful with form to update data that have been created before. Because it will bind the existing value into the default input value. And additionally, it also help to display error that caused by object validation.
If the form is not considered the previous value, like login form, I think the use of plain HTML input will be considered better.

Parameter and view naming collisions in Play/Scala templates

I am new to Play Framework and still trying to wrap my head around some things with the new Scala template engine.
Let's say I have the following package structure:
app/
app/controllers/Items.scala
app/models/Item.scala
app/views/layouts/page.scala.html
app/views/item/show.scala.html
app/views/item/details.scala.html //partial
And this is my item/show template:
#(item: Item, form: Form[Item])(implicit flash: Flash)
#layout.page() {
#*want to include details partial, wont work due to item param*#
#item.details(item)
}
Since including another template (e.g. including item/details above) is the exact same syntax as accessing a template parameter (e.g. item above), obviously this existing naming convention won't work without something changing.
I know I can rename my "app.views.item" package to "app.views.items", and rely on singular/plural forms to differentiate the view from the param name, but this does not seem like a very straightforward solution. Also what if I really want the parameter name to be the same as the view package?
One idea I have is to prepend all my views with an extra top level package:
app/views/views/item/details.scala.html
So the include syntax would be #views.item.details(), but again this is obviously a hack.
What is a good way to avoid this issue? How can I better organize my code to avoid such naming collisions?
Most other template engines use operations like "include" or "render" to specify a partial include. I don't mean to offend anyone here, but is the Play Scala template engine syntax so terse that it actually dictates the organization of code?
3 solutions:
First
Typpicaly for partial templates you should use tags as described in the docs, where app/views/tags folder is a base:
file: app/views/tags/product.scala.html
in the templates (no initial import required in the parent view full syntax will allow you to avoid name-clash: #tags.packageName.tagName()):
<div id="container">
#tags.product(item)
</div>
Of course in your case you can also use packages in the base folder
file: app/views/tags/item/product.scala.html
<div id="container">
#tags.item.product(item)
</div>
I'm pretty sure that'll solve your problem.
Second
To avoid clash without changing package's name you can just rename the item in your view, also I recommend do not use a form name for the Form[T] as it can conflict with helpers:
#(existingItem: Item, existingItemForm: Form[Item])(implicit flash: Flash)
#layout.page() {
#item.details(existingItem)
}
Third
If you'll fill your Form[Item] before passing to the view with given Item object, you don't need to pass both, as most probably you can get data from the form:
#(itemForm: Form[Item])(implicit flash: Flash)
#layout.page() {
<div>Name of item is: #itemForm("name").value (this is a replacemnet for ##existingItem.name </div>
#item.details(itemForm)
}
Of course in you product.scala.html you'll need to change the #(item: Item) param to #(itemForm: Form[Item])

simple database query in lift framework web page

I'm starting out with Lift and been reading a few tutorials and books that are available online. Coming from a JSP (or GWT) background, it's a huge leap, especially since I'm still learning Scala too.
Anyway... I've created the basic site by downloading the lift tar.gz stuff from their site, copied the lift_blank" directory and renamed it to "test". Did the whole "sbt update ~jetty-run" thing etc etc.
What I want to do is modify the "index.html" page to simply have a text field for input, and a button that says "search". Basic idea, you type your firstname, hit "Search", a database query is executed for finding records with a firstname of "what-you-entered-in-the-text-field", and then the results are formatted and displayed on the web page; after the page has refreshed, the text field needs to contain the name that was entered as well.. You type in a different name, hit "search", and new results are displayed on the page. Initially (first time visiting the page), the results are of course empty. Simple stuff...
However, the examples I've all seen use html forms and POST backs etc; I really dislike this, for example users get all flustered when refreshing the page and they get a firefox popup "To display this page, Iceweasel must send information that will repeat any action (such as a search or order confirmation) that was performed earlier."... the page is also refreshed which is something I'd like to avoid.
Previously when I would build this in JSP, I would use all javascript; no "form" tags or anything, just a simple field with javascript events for hitting enter or hitting a "button"... events thaen get channeled to a main javascript function "onQuery" which then creates an AJAX request; when the result comes back from the server, javascript would modify a wrapper "div" element by changing the "innerHTML" value etc. The nice thing here is that the page doesn't refresh, just a tiny subsection of it does, the "table" (actually a div) which holds the results.
How would I re-create a very similar thing in Lift? I'm kind of lost here. I've followed a few examples in the past few days, but again they all use POST / forms. I can handle the scala database querying, and I understand how Lift's templates works, it's just the snippet / comet stuff that I could use a few pointers on.
You can try to use the SHtml.ajaxText function to get the input and to use Wiring on server's side to deal with the request and change automatically the result.
However, with this solution, you no longer need the submit button, but as you don't want a form it should not matter much.
Here is what I think about for the HTML file :
<div id="myHtml" class="lift:surround?with=default;at=content">
<form class="lift:form.ajax">
<input class="lift:SearchForm.name"/>
</form>
Value searched : <span class="lift:SearchForm.display">
</div>
Now on server's side it is a little bit more complicated
class SearchForm{
val name = SHtml.ajaxText("", s=>{ SearchWiring.name.set(s); Noop})
def display = {
WiringUI.apply(SearchWiring.name)(name:String => {"*" #> name} )
}
}
object SearchWiring{
val name = ValueCell("All")
}
I don't know if this is totally rigorous but it is my best thought for your problem. You will find more details about wiring on the official liftweb demo and on Seven Things blog. I hope it will help!
Below is what I ended up using. The one thing I dislike about Lift is all the "magic" that needs to be inserted at various points. I can understand most of this, but the whole " ++ hidden" thing could use some explaining...
The "index.html" page, everything including the "body" tag:
<body class="lift:content_id=main">
<div id="main" class="lift:surround?with=default;at=page">
<lift:Search.search>
Search Query: <query:text/> <query:button/><br/>
<div id="results">
</div>
</lift:Search.search>
</div>
</body>
The "Snippet" code, in a class called "Search.scala" (some of the import statements are unused, a leftover result of attempting different approaches):
package code
package snippet
import scala.xml.{NodeSeq, Text}
import net.liftweb.util._
import net.liftweb.common._
import java.util.Date
import code.lib._
import Helpers._
import common.Main
import common.solr.{Hitlist, Solr}
import net.liftweb.http.{S, StatefulSnippet, SHtml}
import net.liftweb.http.js.JsCmds.SetHtml
import _root_.net.liftweb.http.SHtml._
import _root_.net.liftweb.util.Log
import net.liftweb.http.js.JsCmd
import net.liftweb.http.js.JE.JsRaw
object Search {
def search(xhtml:NodeSeq):NodeSeq = {
var queryText = "(initial)"
def runQuery() = {
println("\n\nQuery: " + queryText)
SetHtml("results", <span>Query: {queryText}</span>)
}//runQuery
ajaxForm(
bind("query", xhtml,
"text" -> text(queryText, queryText = _),
"button" -> submit("Post", runQuery)
) ++ hidden(runQuery _)
)
}//search
}//Search