JavaFX - question regarding binding button's disabled state
- by jamiebarrow
I'm trying to create a dummy application that maintains a list of tasks.
For now, all I'm trying to do is add to the list. I enter a task name in a text box, click on the add task button, and expect the list to be updated with the new item and the task name input to be cleared. I only want to be able to add tasks if the task name is not empty. The below code is my implementation, but I have a question regarding the binding.
I'm binding the textbox's text variable to a string in my view model, and the button's disable variable to a boolean in my view model.
I have a trigger to update the disabled state when the task name changes. When the binding of the task name happens the boolean is updated accordingly, but the button still appears disabled. But then when I mouse over the button, it becomes enabled. I believe this is due to JavaFX 1.3's binding being lazy - only updates the bound variable when it is read.
Also, when I've added the task, I clear the task name in the model, but the textbox's text doesn't change - even though I'm using bind with inverse.
Is there a way to make the textbox's text and the button's disabled state update automatically via the binding as I was expecting?
Thanks,
James
AddTaskViewModel.fx:
package jamiebarrow;
import java.lang.System;
public class AddTaskViewModel {
function logChange(prop:String,oldValue,newValue):Void {
println("{System.currentTimeMillis()} : {prop} [{oldValue}] to [{newValue}] ");
}
public var newTaskName: String on replace old {
logChange("newTaskName",old,newTaskName);
isAddTaskDisabled = (newTaskName == null or newTaskName.trim().length() == 0);
};
public var isAddTaskDisabled: Boolean on replace old {
logChange("isAddTaskDisabled",old,isAddTaskDisabled);
};
public var taskItems = [] on replace old {
logChange("taskItems",old,taskItems);
};
public function addTask() {
insert newTaskName into taskItems;
newTaskName = "";
}
}
Main.fx:
package jamiebarrow;
import javafx.scene.control.Button;
import javafx.scene.control.TextBox;
import javafx.scene.control.ListView;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.scene.layout.HBox;
def viewModel = AddTaskViewModel{};
var txtName: TextBox = TextBox {
text: bind viewModel.newTaskName with inverse
onKeyTyped: onKeyTyped
};
function onKeyTyped(event): Void {
txtName.commit(); // ensures model is updated
cmdAddTask.disable = viewModel.isAddTaskDisabled;// the binding only occurs lazily, so this is needed
}
var cmdAddTask = Button {
text: "Add"
disable: bind viewModel.isAddTaskDisabled with inverse
action: onAddTask
};
function onAddTask(): Void {
viewModel.addTask();
}
var lstTasks = ListView {
items: bind viewModel.taskItems with inverse
};
Stage {
scene: Scene {
content: [
VBox {
content: [
HBox {
content: [
txtName,
cmdAddTask
]
},
lstTasks
]
}
]
}
}