Views
9 months ago

tornadofx-guide

11. Editing Models and

11. Editing Models and Validation Using the ItemViewModel this can be rewritten: // Update the person inside the view model on selection change bindSelected(model) This will effectively attach the listener we had to write manually before and make sure that the TableView selection is visible in the model. The save() function will now also be slightly different, since there is no person property in our model: private fun save() { model.commit() val person = model.item println("Saving ${person.name} / ${person.title}") } The person is extracted from the itemProperty using the item getter. When working with the ItemViewModel() and POJO's starting at 1.7.1 you can create the bindings as follows data class Person(val firstName: String, val lastName: String) class PersonModel : ItemViewModel() { val firstname = bind { item?.firstName?.toProperty() } val lastName = bind { item?.lastName?.toProperty() } } OnCommit callback Sometimes it's desirable to do a specific action after the model was successfully committed. The ViewModel offers two callbacks, onCommit and onCommit(commits: List) , for that. The first function onCommit , has no parameters and will be called after a successful commit, right before the optional successFn is invoked (see: commit ). The second function will be called in the same order and with the addition of passing a list of committed properties along. Each Commit in the list, consists of the original ObservableValue , the oldValue and the newValue and a property changed , to signal if the oldValue is different then the newValue . 164

11. Editing Models and Validation Let's look at an example how we can retrieve only the changed objects and print them to stdout . To find out which object changed we defined a little extension function, which will find the given property and if it was changed will return the old and new value or null if there was no change. class PersonModel : ItemViewModel() { val firstname = bind(Person::firstName) val lastName = bind(Person::lastName) override val onCommit(commits: List) { // The println will only be called if findChanged is not null commits.findChanged(firstName)?.let { println("First-Name changed from ${it.fir st} to ${it.second}")} commits.findChanged(lastName)?.let { println("Last-Name changed from ${it.first } to ${it.second}")} } } private fun List.findChanged(ref: Property): Pair? { val commit = find { it.property == ref && it.changed} return commit?.let { (it.newValue as T) to (it.oldValue as T) } } Injectable Models Most commonly you will not have both the TableView and the editor in the same View . We would then need to access the ViewModel from at least two different views, one for the TableView and one for the form. Luckily, the ViewModel is injectable, so we can rewrite our editor example and split the two views: class PersonList : View("Person List") { val persons = listOf(Person("John", "Manager"), Person("Jay", "Worker bee")).obser vable() val model : PersonModel by inject() } override val root = tableview(persons) { title = "Person" column("Name", Person::nameProperty) column("Title", Person::titleProperty) bindSelected(model) } 165

GUIDE
Guide
GUIDE
GUIDE
GUIDE
Guide
Guide
GUIDE
Guide
GUIDE
Guide
Guide