I have a _flash subtemplate:
#(flash: Flash)
#flash.data.foreach { x =>
#x._1, #x._2
}
This code never shows any flash message. The code below doesn't work either
#if(!flash.isEmpty) {
#for((msgKey, msgValue) <- flash) {
<div class="alert alert-#msgKey" data-dismiss="alert">
<a title="#Messages("misc.message.close")" class="close">×</a>
#msgKey
</div>
}
}
due to the error at runtime: filter is not a member of Flash. And oddly enough, the code below does work and show a message:
#flash.get("success")
How I set the message is not important because it works well in the last case, however, there is the code for it:
if (success) {
Redirect(routes.Application.success).flashing("success" -> "Ok123")
} else {
Ok(views.html.registration.add(newForm))
}
My aim is loop over flash because it want to show all messages in _flash subtemplate.
UPDATE: I realized why the first approach doesn't work (I have to use map instead). But why does the second one raise the error at runtime?
Syntax error, you missed flash.data. From Play 2.0 API we see that Flash is a
case class Flash (data: Map[String, String]) extends Product with Serializable
So the correct code should be:
#if(!flash.isEmpty) {
#for((msgKey, msgValue) <- flash.data) {
<div class="alert alert-#msgKey" data-dismiss="alert">
<a title="#Messages("misc.message.close")" class="close">×</a>
#msgKey
</div>
}
}
I'm almost sure that this is compile-time error, you see it in runtime only because you use dev mode.
BTW, I usually do something like this:
#()(implicit flash: play.api.mvc.Flash)
#flash.get("success").map { message =>
<div class="alert alert-success alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
#message
</div>
}
#flash.get("failure").map { message =>
<div class="alert alert-danger alert-dismissable">
<a class="close" data-dismiss="alert">×</a>
#message
</div>
}
Related
I'm facing an issue while calling a Play Scala controller method with a large amount of data. I have file upload method which takes 2 uploaded files and processes them. If the file size is big, the controller method is getting called twice. If the file size is less, it works fine and is getting called only once. I'm not sure what is happening behind the scene.
routes.conf
POST /test/upload controllers.TestController.upload(id:Int, isTest: Boolean)
TestController.scala
def upload(id: Int, isTest: Boolean) = Action(parse.multipartFormData) { implicit request: Request[play.api.mvc.MultipartFormData[play.api.libs.Files.TemporaryFile]] =>
.....
.....
}
upload.scala.html
#helper.form(action = routes.TestController.upload(form.id, isTest), 'enctype -> "multipart/form-data") {
<div class="form-group">
<label for="file1">File 1:</label>
<input class='btn btn-outline btn-primary' name="file1" type="file" data-preview-file-type="text" >
</div>
<div class="form-group">
<label for="file1">File 2:</label>
<input class='btn btn-outline btn-primary' name="file2" type="file" data-preview-file-type="text" >
</div>
<button type="submit" class="btn btn-default btn-primary" id="uploadButton" onclick="$('#myPleaseWait').modal('show');">
Upload</button>
}
Any help on why the method is getting called twice will be helpful.
Several days ago I read about binding.scala and I found it so cool therefore I decided to write my own single page app.
The problem is that I'm trying to add "li" items into "ul" element, but it seems like the component Want doesn't see updates.
The code below:
case class Movie(title: Var[String], raring: Var[Int], watched: Var[Boolean])
var movies = Vars.empty[Movie]
#dom def Want = {
println(movies.bind, "!##!##!##!")
<div class="want">
<ul>
{for (movie <- movies.value) yield {
<li>
<div>
<span>
{movie.title.bind}
</span>
<button onclick={event: Event => {
event.preventDefault()
movies.value.remove(movies.value.indexOf(movie))
println(movies.value)
}}></button>
</div>
</li>
}}
</ul>
</div>
When I change movies nothing happens.
UPDATE
After the comment below I updated the code:
def remove(movie:Movie) = {
movies.value.-=(movie)}
#dom def Want = {
println(movies, "!##!##!##!")
<div class="want">
<ul>
{for (movie <- movies.bind) yield {
<li>
<div>
<span>
{movie.title.bind}
</span>
<button onclick={event: Event => {
event.preventDefault()
remove(movie)
}}></button>
</div>
</li>
}}
</ul>
</div>
}
However, the code doesn't work.
Please change for (movie <- movies.value) to for (movie <- movies).
According to the Scaladoc of value method:
Note: This method must not be invoked inside a #dom method body.
I'm using play! framework with scala to deploy a web application.
I would like to open a popup message when an User fail to login.
This is my scala template code:
#form(routes.Application.login) {
<div class="emailaddress">E-mail address:</div>
<div class="inputbox">
#helper.input(userForm("email"), '_id -> "email", '_label->"" ) { (id, name, value, args) =>
<input placeholder="Insert email" type="text" class="email-input" id="#id" name="#name" value="" #toHtmlArgs(args)>
}
</div>
<div class="password">Password:</div>
<div class="inputbox1">
#helper.input(userForm("password"), '_id -> "password", '_label->"") { (id, name, value, args) =>
<input placeholder="Insert password" class="password-input" type="password" id="#id" name="#name" value="" #toHtmlArgs(args)>
}
</div>
<div >
<button id="submit-button" class="myButton" >Submit</button>
</div>
#if(userForm.hasGlobalErrors) {
<div class="alert alert-error">
<a class="close" data-dismiss="alert">×</a>
function to javascriptPopUp(#userForm.globalError.get.message);
</div>
}
}
and my controller code is :
def login = Action { implicit request =>
userForm.bindFromRequest.fold(
errors=> BadRequest(views.html.user.userLogin(UserDB.findAll, errors)),
user => {
val use = UserDB.findUserByLogin(user.email, user.password)
if(use!=None){
Redirect(routes.DataManagementController.projects).withSession(Security.username -> user.email).flashing("success" -> "You've been logged in")
}else{
Ok(views.html.user.userLogin(UserDB.findAll, userForm))
}
}
)
}
But even with error it never gets to my javascript function.
Can anybody explain to me why I never get in?
(if you need more code, ask and I will post it, I'm just saving space on this page because Login works, I can't just show message errors).
I have following View:
#model DocuLive.ViewModels.InstallationRequestViewModel
#{
ViewBag.Title = "AttachDB";
Layout = "~/Views/Shared/_AdminPage.cshtml";
}
<h2>AttachDB</h2>
#using (Html.BeginForm("AttachDB","AppStart", FormMethod.Post)) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<p>Database DocuLive already exists on the server where you attempted installation. Do wish to attach existing DB to this installation of DocuLive? Details below will be used for this attempt.</p>
<fieldset>
<p>
<input type="submit" name="command" value="Attach" />
<input type="submit" name="command" value="Start over" />
</p>
<legend>DB server credentials</legend>
<div class="display-label">
#Html.DisplayNameFor(model => model.Server)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.Server)
</div>
<div class="display-label">
#Html.DisplayNameFor(model => model.UserName)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.UserName)
</div>
<div class="display-label">
#Html.DisplayNameFor(model => model.Password)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.Password)
</div>
</fieldset>
}
I have follownt two methods in controller:
public ActionResult AttachDB(InstallationRequestViewModel requestVM)
{
if (requestVM != null)
return View("AttachDB", requestVM);
else
{
TempData["Fail"] = "DocuLive database exist, but inicalization request has null value and cannot be used to attach DB";
return RedirectToAction("Index");
}
}
[HttpPost]
private async Task<ActionResult> AttachDB(InstallationRequestViewModel requestVM, string command)
{
try
{
switch (command)
{
case "Attach":
// do something complex and return RedirectToAction
case "Start over":
return RedirectToAction("Index");
default:
return RedirectToAction("Index");
}
}
catch (Exception ex)
{
TempData["Fail"] = ex.Message;
return RedirectToAction("Index");
}
}
For some reason when i submit the form with either button, it hits the first method with no regard to fact that I explicitly specified FormMethod.Post for the form to make sure that submitting the form will take user to the second method that actually contains some business logic.
It is very strange because I am using similar approach all over the app and so far I had no issues with this.
Can anyone advise, why submitting the form with either button is considered Get instead of POST?
Thanks in advance...
Found it. I made the second method private by accident. Pretty stupid mistake...
I've added this to my Boot.scala
LiftRules.viewDispatch.append({
case List("admin", "categories") => Right(Admin)
})
Here is my Admin.scala in (admin/view package)
object Admin extends LiftView{
def dispatch = {
case "add" => editCategory
}
def editCategory(): NodeSeq = {
<lift:embed what="/admin/add_category"></lift:embed>
}
}
Here is my add_category template -
<lift:surround with="admin" at="content">
<div class="container-fluid" id="main_container">
<lift:Admin:addCategory form="POST" class="form-horizontal">
<fieldset>
<legend>Add Category</legend>
<div class="control-group">
<label class="control-label" for="cat_name">Name</label>
<div class="controls">
<cat:name></cat:name>
</div>
</div>
<div class="control-group">
<label class="control-label" for="cat_desc">Description</label>
<div class="controls">
<cat:desc></cat:desc>
<cat:submit></cat:submit>
</div>
</div>
</fieldset>
</lift:Admin:addCategory>
</div>
</lift:surround>
I'm trying to bind this with a snippet -Admin.scala in (admin/snippet package) with addCategory method.
object name extends RequestVar("")
object desc extends RequestVar("")
def addCategory(in: NodeSeq): NodeSeq = {
def doAdd() {
//todo: Save Category
}
bind("cat", in,
"name" -> SHtml.text(name.is, (n: String) => name(n), ("id", "cat_name"), ("class", "input-large")),
"desc" -> SHtml.textarea(desc.is, (d: String) => desc(d), ("id", "cat_desc"), ("class", "input-large")),
"submit" -> SHtml.submit("Save", doAdd, ("class", "btn btn-info"))
)
}
I'm getting this error -
Error processing snippet: admin:addcategory
Reason: Method Not Found
XML causing this error:
<lift:admin:addcategory class="form-horizontal" form="POST">
<fieldset>
<legend>Add Category</legend>
<div class="control-group">
<label for="cat_name" class="control-label">Name</label>
<div class="controls">
<cat:name></cat:name>
</div>
</div>
<div class="control-group">
<label for="cat_desc" class="control-label">Description</label>
<div class="controls">
<cat:desc></cat:desc>
<cat:submit></cat:submit>
</div>
</div>
</fieldset>
</lift:admin:addcategory>
And in the logs -
[net.liftweb.http.LiftRules] - Snippet Failure: SnippetFailure(/admin/categories/add -> ParsePath(List(admin, categories, add),,true,false),Full(admin:addcategory),Method Not Found)
Need help with this. I'm unable to figure out why lift is not able to find the method.
Have you added your admin package into LiftRules? Something like this should allow Lift to search admin.snippets for resolution:
LiftRules.addToPackages("admin")
Also, I believe you need to be calling the snippet as Admin.addCategory instead of with a :.
Edit:
I believe that the Lift HTML5 parser was case sensitive and had trouble with camel case method names. You may want to try renaming your method to all lowercase, or try calling your snippet as (instead of with the <lift: style):
<div class="lift:admin.addCategory"> ... </div>
or
<div data-lift="admin.addCategory"> ... </div>