I am very close to finish my to do list application but there is a slight error - scala

This is a to-do list application that i made as a beginner. However, there is an error that says missing parameter type in this line of code:
todoTable.selectionModel().selectedItem.onChange(
(_, newValue) => showTodoDetails(Some(newValue))
)
I can't figure out what the problem is as I had no issue running with it earlier. And it also seems to be the only error that keeps me from finishing the to-do application program.
Below is the file that is having an error
package ch.makery.address.view
import ch.makery.address.model.Todo
import ch.makery.address.MainApp
import scalafx.scene.control.{Alert, Label, TableColumn, TableView}
import scalafxml.core.macros.sfxml
import scalafx.beans.property.StringProperty
import scala.util.{Failure, Success}
import scalafx.Includes._
import scalafx.event.ActionEvent
import scalafx.scene.control.Alert.AlertType
#sfxml
class TodoOverviewController(
private val todoTable : TableView[Todo],
private val titleColumn : TableColumn[Todo, String],
private val titleLabel : Label,
private val descriptionLabel : Label
) {
// initialize Table View display contents model
todoTable.items = MainApp.todoData
// initialize columns's cell values
titleColumn.cellValueFactory = {_.value.title}
showTodoDetails(None);
todoTable.selectionModel().selectedItem.onChange(
(_, newValue) => showTodoDetails(Some(newValue))
)
private def showTodoDetails (todo : Option[Todo]) = {
todo match {
case Some(todo) =>
// Fill the labels with info from the todo object.
titleLabel.text <== todo.title
descriptionLabel.text <== todo.description
case None =>
// todo is null, remove all the text.
titleLabel.text = ""
descriptionLabel.text = ""
}
}
def handleNewTodo(action : ActionEvent) = {
val todo = new Todo("")
val okClicked = MainApp.showTodoEditDialog(todo);
if (okClicked) {
todo.save() match {
case Success(x) =>
MainApp.todoData += todo
case Failure(e) =>
val alert = new Alert(Alert.AlertType.Warning) {
initOwner(MainApp.stage)
title = "Failed to Save"
headerText = "Database Error"
contentText = "Database problem filed to save changes"
}.showAndWait()
}
}
}
def handleEditTodo(action : ActionEvent) = {
val selectedTodo = todoTable.selectionModel().selectedItem.value
if (selectedTodo != null) {
val okClicked = MainApp.showTodoEditDialog(selectedTodo)
if (okClicked) {
selectedTodo.save() match {
case Success(x) =>
showTodoDetails(Some(selectedTodo))
case Failure(e) =>
val alert = new Alert(Alert.AlertType.Warning) {
initOwner(MainApp.stage)
title = "Failed to Save"
headerText = "Database Error"
contentText = "Database problem filed to save changes"
}.showAndWait()
}
}
} else {
// Nothing selected.
val alert = new Alert(Alert.AlertType.Warning){
initOwner(MainApp.stage)
title = "No Selection"
headerText = "No Todo Selected"
contentText = "Please select a todo in the table."
}.showAndWait()
}
}
def handleDeleteTodo(action : ActionEvent) = {
val selectedIndex = todoTable.selectionModel().selectedIndex.value
val selectedTodo = todoTable.selectionModel().selectedItem.value
if (selectedIndex >= 0) {
selectedTodo.save() match {
case Success(x) =>
todoTable.items().remove(selectedIndex);
case Failure(e) =>
val alert = new Alert(Alert.AlertType.Warning) {
initOwner(MainApp.stage)
title = "Failed to Save"
headerText = "Database Error"
contentText = "Database problem filed to save changes"
}.showAndWait()
}
} else {
// Nothing selected.
val alert = new Alert(AlertType.Warning){
initOwner(MainApp.stage)
title = "No Selection"
headerText = "No Todo Selected"
contentText = "Please select a todo in the table."
}.showAndWait()
}
}
}

The function passed to onChange takes 3 arguments, not 2, you should have
todoTable.selectionModel().selectedItem.onChange(
(_, _, newValue) => showTodoDetails(Some(newValue))
)

Related

Play Framework - Respond with JSON after uploading a file (multipartFormData)

I am using this code to upload an image on server , that i get from this link play upload
def upload = Action(parse.multipartFormData) { request =>
request.body
.file("picture")
.map { picture =>
val dataParts = request.body.dataParts;
val filename = Paths.get(picture.filename).getFileName
val fileSize = picture.fileSize
val contentType = picture.contentType
val picturePaths =
picture.ref.copyTo(
Paths.get(
s"/opt/docker/images/$filename"
),
replace = true
)
if (dataParts.get("firstPoint") == None) {
val pointlocation = new Point_LocationModel(
dataParts.get("step").get(0),
dataParts.get("backgroundTargetName").get(0),
dataParts.get("x").get(0),
dataParts.get("y").get(0),
dataParts.get("z").get(0),
dataParts.get("rotation").get(0),
dataParts.get("note").get(0),
dataParts.get("tag").get(0),
dataParts.get("work_session_id").get(0),
(picturePaths).toString
)
point_LocationRepository.create(pointlocation).map { data =>
Created(Json.toJson(data._2))
}
} else {
val jValuefirstPoint =
Json.parse(dataParts.get("firstPoint").get(0)).as[PointModel]
val jValuesecondPoint =
Json.parse(dataParts.get("secondPoint").get(0)).as[PointModel]
val pointlocation = new Point_LocationModel(
dataParts.get("step").get(0),
dataParts.get("backgroundTargetName").get(0),
Some(jValuefirstPoint),
Some(jValuesecondPoint),
dataParts.get("rotation").get(0),
dataParts.get("note").get(0),
dataParts.get("tag").get(0),
dataParts.get("work_session_id").get(0),
(picturePaths).toString
)
point_LocationRepository.create(pointlocation).map { data =>
logger.info(s"repoResponse: ${data}");
Created(Json.toJson(data._2))
}
}
Ok(s"picturePaths ${picturePaths}")
}
.getOrElse(Ok("Invalid Format"))
}
This code works very well, but on the response I want to get the response from the repository. How can i await for the response of the repository to return this?
Can you give me any idea how can i do it?
Thanks in advance.
If we simplify your code to the essential bits, you have:
def upload = Action(parse.multipartFormData) { request =>
request.body
.file("picture")
.map { picture =>
if (someConditionA) {
someBusinessLogicA().map { data =>
Created(Json.toJson(data._2))
}
} else {
someBusinessLogicB().map { data =>
Created(Json.toJson(data._2))
}
}
Ok(s"picturePaths ${picturePaths}")
}
.getOrElse(Ok("Invalid Format"))
}
There are 2 problems:
the return of your if/else is swallowed by the Ok(s"picturePaths ${picturePaths}")
assuming your business logic returns Future[_] you need to "propagate" the Future everywhere
Something like this should work:
def upload = Action.async(parse.multipartFormData) { request =>
request.body
.file("picture")
.map { picture =>
if (someConditionA) {
someBusinessLogicA().map { data =>
Created(Json.toJson(data._2))
}
} else {
someBusinessLogicB().map { data =>
Created(Json.toJson(data._2))
}
}
}
.getOrElse(Future.successful(Ok("Invalid Format")))
}
Notice the Action.async and the Future in the getOrElse.

Setting state in ajax success in scalajs-react

I am trying to open one popup on successful submission of another in scalajs-react. My problem is on success state is not getting modified. Here is my addNewAgent method called as a callback on submission of first popup.
def addNewAgent(userModel: UserModel, addNewAgent: Boolean = false): Callback = {
println(addNewAgent)
if(addNewAgent){
createUser(userModel).onComplete {
case Success(s) =>
println(s.msgType)
if (s.msgType == ApiResponseMsg.CreateUserWaiting){
t.modState(s => s.copy(showNewAgentForm = false, showConfirmAccountCreation = true))
} else {
t.modState(s => s.copy(showNewAgentForm = false, showRegistrationFailed = true))
}
case Failure(s) =>
println(s)
t.modState(s => s.copy(showRegistrationFailed = true))
// now you need to refresh the UI
}
t.modState(s => s.copy(showNewAgentForm = false))
} else {
t.modState(s => s.copy(showNewAgentForm = false))
}
}
and component code is :
val component = ReactComponentB[Props]("AddNewAgent")
.initialState(State()) // initial state from TodoStore
.backend(new Backend(_))
.renderPS(($, P, S) => {
val B = $.backend
<.div()(
Button(Button.Props(B.addNewAgentForm(), CommonStyle.default, Seq(HeaderCSS.Style.SignUpBtn)),"Sign Up"),
if (S.showNewAgentForm) NewAgentForm(NewAgentForm.Props(B.addNewAgent))
else if (S.showConfirmAccountCreation ) ConfirmAccountCreation(ConfirmAccountCreation.Props(B.confirmAccountCreation))
else
Seq.empty[ReactElement]
)
})
// .componentDidMount(scope => scope.backend.mounted(scope.props))
.configure(OnUnmount.install)
.build
def apply(props: Props) = component(props)
For anyone looking for an answer to this problem what is happening here is that
the modState calls inside the future completion will never be really called
because they return a Callback that don't run. To solve this you need to add runNow() like t.modState(s => s.copy(showNewAgentForm = false, showRegistrationFailed = true)).runNow()

Make progress bar visible when query is loading. ScalaFx

I have a login window view, and I want to display a progress bar when I click/press enter button while slick is querying the password. If I change the visible attribute for the progress bar at the button actionEvent it doesn´t appear until after the query is done. Also I don't want the progress bar to be taking space while its invisible. Does anybody know how to do these things?
object SPM extends JFXApp {
/*
* Primary stage: Log in
* */
stage = new PrimaryStage {
// error message hidden label
val errorLabel = new Label()
errorLabel.textFill = Color.Red
errorLabel.font = Font.font("Helvetica", FontWeight.ExtraLight, 12)
val usernameField = new TextField {
promptText = "User"
maxWidth = 250
prefHeight = 35
}
val passwordField = new PasswordField() {
promptText = "Password"
maxWidth = 250
prefHeight = 35
}
val progressBar = new ProgressBar {
maxWidth = 300
visible = false
}
title = "Software Project Management"
scene = new Scene(800, 600) {
root = new VBox {
spacing = 10
padding = Insets(20)
alignment = Pos.Center
children = List(
new ImageView {
image = new Image(
this.getClass.getResourceAsStream("/images/logo.png"))
margin = Insets(0, 0, 20, 0)
},
new Label {
text = "Software Project Management"
font = Font.font("Helvetica", FontWeight.ExtraLight, 32)
},
new Label {
text = "Sign in to get started"
font = Font.font("Helvetica", FontWeight.Thin, 18)
},
errorLabel,
progressBar,
usernameField,
passwordField,
new Button {
text = "Enter"
defaultButton = true
prefHeight = 35
font = Font.font("Helvetica", FontWeight.Thin, 18)
maxWidth = 250
onAction = (ae: ActionEvent) => {
progressBar.visible = true
val password = Users.checkPassword(usernameField.text.value)
if (password != passwordField.text.value)
errorLabel.text = "Please re-enter your password"
else root = chooseProject
}
}
) // children
} // root
} // scene
Your Button.onAction handler is running on JavaFX application thread. The same that is used to update UI. When you run long running task you should run it on a separate thread it will help UI to react properly. The common way to do that is to use JavaFX Task. General pattern is like this:
// Define your task
val task = new javafx.concurrent.Task[T] {
override def call(): T = {
// Do your task and return result
// Executed off JavaFX Application thread
}
override def succeeded(): Unit = {
// Update UI to finish processing
// Executed on JavaFX Application thread
}
override def failed(): Unit = {
// Handle errors, if any
// Executed on JavaFX Application thread
}
}
// Run your task
val t = new Thread(task, "My Task")
t.setDaemon(true)
t.start()
```
Here is how it could look in your code:
root = new VBox { _root =>
...
onAction = (ae: ActionEvent) => {
progressBar.visible = true
_root.disable = true
// progressBar.visible = true
val task = new javafx.concurrent.Task[Boolean] {
override def call(): Boolean = {
println("Checking password... ")
Thread.sleep(3000)
println("Password checked. ")
// Assume password is correct
true
}
override def succeeded(): Unit = {
progressBar.visible = false
_root.disable = false
val passwordOK = get()
if (passwordOK) {
new Alert(AlertType.Information) {
headerText = "Password OK"
}.showAndWait()
} else {
new Alert(AlertType.Warning) {
headerText = "Invalid Password"
}.showAndWait()
}
}
override def failed(): Unit = {
println("failed")
progressBar.visible = false
_root.disable = false
}
}
val t = new Thread(task, "Password Task")
t.setDaemon(true)
t.start()
}

how to create an updateable tableview cell in Scala

I have created a tableview with their components inside it, assigned cellValueFactory and have set the properties editable to true. Somewhere in my code, I have the following :
...
tableID.selectionModel().selectedItem.onChange(
(_, _, newValue) => col_uname.setCellFactory(TextFieldTableCell.forTableColumn());
...
With it, I managed to create to convert it to textfield and are allowed to type in it. However,after finishing typing, the text reversed back to previous text before the edit. What type/piece of code should I include make sure that the text is updated properly?
I've tried searching on google, but there's no explanation for it so far.
You should be able to edit table by, as you mentioned, editable = true and adding cell factory with a text field, for instance:
new TableColumn[Person, String] {
text = "First Name"
cellValueFactory = {_.value.firstName}
cellFactory = TextFieldTableCell.forTableColumn()
prefWidth = 180
}
The JavaFX Table View Tutorial also suggests using OnEditCommit. Not sure if that is really necessary. Here is a complete example that works without using OnEditCommit:
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.beans.property.StringProperty
import scalafx.collections.ObservableBuffer
import scalafx.event.ActionEvent
import scalafx.scene.Scene
import scalafx.scene.control.TableColumn._
import scalafx.scene.control.cell.TextFieldTableCell
import scalafx.scene.control.{Button, TableColumn, TableView}
import scalafx.scene.layout.VBox
object EditableTableView extends JFXApp {
class Person(firstName_ : String, lastName_ : String) {
val firstName = new StringProperty(this, "firstName", firstName_)
val lastName = new StringProperty(this, "lastName", lastName_)
firstName.onChange { (_, oldValue, newValue) => println(s"Value changed from `$oldValue` to `$newValue`") }
lastName.onChange { (_, oldValue, newValue) => println(s"Value changed from `$oldValue` to `$newValue`") }
override def toString = firstName() + " " + lastName()
}
val characters = ObservableBuffer[Person](
new Person("Peggy", "Sue"),
new Person("Rocky", "Raccoon")
)
stage = new PrimaryStage {
title = "Editable Table View"
scene = new Scene {
root = new VBox {
children = Seq(
new TableView[Person](characters) {
editable = true
columns ++= List(
new TableColumn[Person, String] {
text = "First Name"
cellValueFactory = {_.value.firstName}
cellFactory = TextFieldTableCell.forTableColumn()
prefWidth = 180
},
new TableColumn[Person, String]() {
text = "Last Name"
cellValueFactory = {_.value.lastName}
cellFactory = TextFieldTableCell.forTableColumn()
prefWidth = 180
}
)
},
new Button {
text = "Print content"
onAction = (ae: ActionEvent) => {
println("Characters:")
characters.foreach(println)
}
}
)
}
}
}
}

Scala Swing Wait

//Main.scala
/* imports */
object Main extends SimpleSwingApplication {
lazy val ui = new TabbedPane {
/* contents */
}
def top = new MainFrame {
/* contents */
}
override def startup(args: Array[String]) {
val t = top
val loginStatus = new Login(t).status
if (loginStatus == true) {
if (t.size == new Dimension(0, 0)) t.pack
t.visible = true
} else
quit
}
}
//Login.scala
class Login(owner: Window) extends Dialog(owner) {
import Login._
var status = true
contents = ui
listenTo(login) //login is a Button
reactions += {
case ButtonClicked(login) => {
if (/* login field is empty */)
status = false
else if (/* login info is correct */)
status = true
else /*login info is wrong*/
status = false
}
}
}
How can I have 'Main' to wait for 'Login' before displaying itself?
Use a CountDownLatch:
//Main.scala
/* imports */
object Main extends SimpleSwingApplication {
private val latch = new CountDownLatch(1)
lazy val ui = new TabbedPane {
/* contents */
}
def top = new MainFrame {
/* contents */
}
override def startup(args: Array[String]) {
val t = top
val loginDialog = new Login(t, latch)
latch.await
val loginStatus = loginWindow.status
if (loginStatus == true) {
if (t.size == new Dimension(0, 0)) { t.pack }
t.visible = true
} else
quit
}
}
//Login.scala
class Login(owner: Window, latch: CountDownLatch) extends Dialog(owner) {
import Login._
var status = true
contents = ui
listenTo(login) //login is a Button
reactions += {
case ButtonClicked(login) => {
latch.countdown
if (/* login field is empty */)
status = false
else if (/* login info is correct */)
status = true
else /*login info is wrong*/
status = false
}
}
}