Why is image-src method-return-type instead of URL/route for Play Framework Module Controller? - scala

I have created a Play Framework module "Ean2BarcodePlayModule" which includes this template "barcode.scala.html" saved in the "views.barcodePackage.tags" package:
#(ean: Long)
<img class="barcode" alt="#ean" src="#controllers.barcodePackage.BarcodeController.getBarcode(ean)" />
After using "activator publish-local", I've then referenced this in the "index.scala.html" template of a test project:
#(message: String)
#main("Welcome to Play") {
#barcodePackage.tags.barcode(5010255079763L)
}
The expected result is
<!-- Redacted for brevity -->
<img class="barcode" alt="5010255079763" src="/barcodeRoutes/5010255079763">
<!-- Redacted for brevity -->
But the actual result is:
<!-- Redacted for brevity -->
<img class="barcode" alt="5010255079763" src="Action(parser=BodyParser(anyContent))">
<!-- Redacted for brevity -->
As will be noted, the controller's action method method's return-type appears where instead the source URL should be, but I don't understand why that is happening or know how to fix it.
The module includes this line in "barcodePackage.routes":
GET /:ean controllers.barcodePackage.BarcodeController.getBarcode(ean:Long)
Meanwhile, the route file in the test project contains:
-> /barcodeRoutes barcodePackage.Routes
This is the code for the module controller:
package controllers.barcodePackage
import models.barcodePackage.Barcode
import play.api.mvc.{Action, Controller}
import play.api.libs.concurrent.Execution.Implicits._
import scala.util.{Failure, Success}
/**
* Created by Brian_Kessler on 3/11/2015.
*/
object BarcodeController extends Controller
{
def getBarcode(ean:Long) = Action.async{
Barcode.renderImage(ean) map {
case Success(imageData) => Ok(imageData).as(Barcode.mimeType)
case Failure(error) => BadRequest("Couldn't generate bar code. Error: " + error.getMessage)
}
}
}
Notes:
Most importantly, I'd like to see the module functionality working as expected.
But I'd also prefer a solution which allows me to successfully specify routes within the module, rather than be required to transcribe them all individually within projects which incorporate the module.

With thanks to Sarvesh Kumar Singh whose response helped put me on the right track, I've figured this out.
So, as I came to understand, the problem was not that the template was not finding the controller, but rather that it was calling the method in the controller instead of the reverse router for the controller.
So, what I really needed to do was tweak the module's template (all the other changes were probably irrelevant) to make sure it called the router instead.
With my present version of play, this meant changing barcode.scala.html to:
#(ean: Long)
<img class="barcode" alt="#ean" src="#controllers.barcodePackage.routes.BarcodeController.getBarcode(ean:Long)" />
Note, the source does NOT start with "#routes", but rather "routes" comes between the package name ("barcodePackage") and the controller name ("BarcodeController").

That is because, your are calling this function by saying #controllers.net.nowhereatall.playforscala.barcodes.barcode(ean), when template is being rendered by play.
Now as you have already specified a route and have bound it to your controllers.net.nowhereatall.playforscala.barcodes.barcode(ean) function.
Change the filename barcode.routes to barcodes.routes
Now, assuming that you have/want to integrated the barcodes.routes file of your sub-project in the main project as follows,
-> /barcodes barcodes.routes
So... now, you will need to change few things.
Move your controllers in barcodes sub-project under the package controllers.barcodes.
You should use Barcodes and not barcodes for object name ( Scala conventions ).
So your controllers.net.nowhereatall.playforscala.barcodes controller should ideally here - controllers.barcodes.Barcodes. But you can place it here -controllers.barcodes.net.nowhereatall.playforscala.Barcodesif you want, just add the part.net.nowhereatall.playforscala` everywhere in the following code.
Now, change the route in your barcodes.routes,
GET /:ean controllers.barcodes.Barcodes.barcode(ean:Long)
Now, you need to do is to specify this route in your twirl template by using the reverse router.
#(ean: Long)
<img class="barcode" alt="#ean" src="#controllers.barcodes.routes.Barcodes.barcode(ean)" />
Now, when the tempate is reandered by play by #barcodes.tags.barcode(5010255079763L), this controllers.barcodes.routes.Barcode(ean) call will be evaluated to /barcodes/5010255079763 by the reverse router ( since you bound the controllers.barcodes.Barcode(ean) to / route ).
hence what you will get in browser is,
<img class="barcode" alt="5010255079763" src="/barcodes/5010255079763" />
You can even get it working by hardcoding the route as given below,
#(ean: Long)
<img class="barcode" alt="#ean" src="/barcodes/#ean" />

Related

Visual Studio Code with Native Script does not recognize all Native Script components

Visual Studio Code with Native Script does not recognise Native Script components sometimes in the component XML. I have one from the official tutorial and in it the ActionBar is recognized - but GridLayout is not:
'GridLayout' is not a known element:
1. If 'GridLayout' is an Angular component, then verify that it is part of this module.
2. To allow any element add 'NO_ERRORS_SCHEMA' to the '#NgModule.schemas' of this component.
XML looks like this:
<ActionBar title="Groceries">
<!-- On iOS devices, <ActionItem>s are placed from left to right in sequence; you can override that (as the code above does) by providing an ios.position attribute. -->
<ActionItem text="Share" (tap)="share()" android.systemIcon="ic_menu_share_holo_dark" ios.systemIcon="9" ios.position="right"></ActionItem>
</ActionBar>
<GridLayout rows="auto, *">
<!-- add-bar necessary since we moved the page up 20 over the status bar on iOS-->
<GridLayout row="0" columns="*, auto" class="add-bar">
<TextField #groceryTextField [(ngModel)]="grocery" hint="Enter a grocery item" (returnPress)="add()" col="0"></TextField>
<Image src="res://add" (tap)="add()" col="1"></Image>
</GridLayout>...
It seems totally arbitrary since for example StackLayout is no problem in another XML in same project.
As suggested in the error log make sure that you have included NO_ERRORS_SCHEMA in the respective NgModule (if using lazily loaded modules include the schema there as well)
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
#NgModule({
schemas: [NO_ERRORS_SCHEMA],
//... more code follows here
Side note: it might be just an incomplete snippet but still... the parent GridLayout does not have an enclosing tag
In my case, it was happening just for one component html though NO_ERRORS_SCHEMA was included in respective module of that file, deleting and creating that file solved the issue for me strange but it did happen.

Forms in Scala play framework

Hello i am a beginner to scala play framework. I am unable to create form with two or more inputs. i googled it and found none in scala programming language. Kindly suggest me an idea regarding how to create multiple inputs in a form using scala. i did this
val form = Form (tuple
(
"firstname"-> text,
"lastname" -> text
)
) and to get the values val(fname,lname) = form.bindFromRequest.get
am i following correct way. Kindly suggest me any idea or resource to learn scala play framework . Thanks in advance
Here is a complete (but simple) form example for Play 2.1.1. Including the view, controller and routes file. I suspect you were missing imports and / or an implicit request. Both of which would be understandable!
The controller (Application.scala):
package controllers
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
object Application extends Controller {
val form = Form(
tuple(
"firstname" -> text,
"lastname" -> text
)
)
def index = Action {
Ok(views.html.index())
}
def submit = Action { implicit request =>
val (fname, lname) = form.bindFromRequest.get
Ok("Hi %s %s".format(fname, lname))
}
}
The view (index.scala.html):
<!DOCTYPE html>
<html>
<head>
<title>Form example</title>
</head>
<body>
<form method="post" autocomplete="on">
First name:<input type="text" name="firstname"><br>
Last name: <input type="text" name="lastname"><br>
<input type="submit">
</form>
</body>
</html>
And the routes:
GET / controllers.Application.index
POST / controllers.Application.submit
NB: The name attributes in your HTML view must match the string literals in your controller form.
Hope that helps.
Play documentation is the best way to learn about forms
https://www.playframework.com/documentation/2.1.1/ScalaForms if you want more then, please have a look at play-example-form project.
http://typesafe.com/activator/template/play-example-form This activator example project on forms explains everything about forms.
1) It explains forms and data binding, validation in the play controller.
2) It explains about Optional parameters in the forms.
3) It explains about complex forms with nested objects for example
case class Student(name: String, age: Int, gender: Optional[Char] = None,
address: Address, other: OtherStuff)
The above case class depends on Address, OtherStuff and
notice that the gender is optional. The example project explains how to deal with such complex object dependencies.
Please download activator from here http://typesafe.com/get-started . then, start the activator in browser UI mode using the command activator ui and type play-example-form in the search to download it. After downloading go to the project root folder and type activator eclipse in case you use eclipse or activator gen-idea in case you Intellij Idea.

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])

Creating a custom field constructor in Play 2 (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

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