Views
2 weeks ago

tornadofx-guide

11. Editing Models and

11. Editing Models and Validation Another big change in this version is that the data in the table does not update when we type into the text fields. This is because the model has exposed a copy of the properties from the person object and does not write back into the actual person object before we call model.commit() . This is exactly what we do in the save function. Once commit has been called, the data in the facade is flushed back into our person object and the table will now reflect our changes. Rollback Since the model holds a reference to the actual Person object, we can can reset the text fields to reflect the actual data in our Person object. We could add a reset button like this: button("Reset").action { } model.rollback() When the button is pressed, any changes are discarded and the text fields show the actual Person object values again. The PersonModel We never explained how the PersonModel works yet, and you probably have been wondering about how the PersonModel is implemented. Here it is: class PersonModel(var person: Person) : ViewModel() { val name = bind { person.nameProperty } val title = bind { person.titleProperty } } It can hold a Person object, and it has defined two strange-looking properties called name and title via the bind delegate. Yeah it looks weird, but there is a very good reason for it. The { person.nameProperty } parameter for the bind function is a lambda that returns a property. This returned property is examined by the ViewModel , and a new property of the same type is created. It is then put into the name property of the ViewModel . When we bind a text field to the name property of the model, only the copy is updated when you type into the text field. The ViewModel keeps track of which actual property belongs to which facade, and when you call commit the values from the facade are flushed into the actual backing property. On the flip side, when you call rollback the exact opposite happens: The actual property value is flushed into the facade. 158

11. Editing Models and Validation The reason the actual property is wrapped in a function is that this makes it possible to change the person variable and then extract the property from that new person. You can read more about this below (rebinding). Dirty Checking The model has a Property called dirty . This is a BooleanBinding which you can observe to enable or disable certain features. For example, we could easily disable the save button until there are actual changes. The updated save button would look like this: button("Save") { enableWhen(model.dirty) action { save() } } There is also a plain val called isDirty which returns a Boolean representing the dirty state for the entire model. One thing to note is that if the backing object is being modified while the ViewModel is also modified via the UI, all uncommitted changes in the ViewModel are being overridden by the changes in the backing object. That means the data in the ViewModel might get lost if external modification of the backing object takes place. val person = Person("John", "Manager") val model = PersonModel(person) model.name.value = "Johnny" person.name = "Johan" //modify the ViewModel //modify the underlying object println(" Person = ${person.name}, ${person.title}") //output: Person = Johan, Manager println("Is dirty = ${model.isDirty}") //output: Is dirty = false println(" Model = ${model.name.value}, ${model.title.value}") //output: Model = Johan, Manager As can be seen above the changes in the ViewModel got overridden when the underlying object was modified. And the ViewModel was not flagged as dirty . Dirty Properties 159

Guide
guide
GUIDE
GUIDE
GUIDE
Guide
Guide
GUIDE
guide
guide
Guide
Guide
GUIDE
GUIDE
GUIDE
Guide
Guide
The Guide
guide
Guide
guide
Guide
GUIDE TO
guide
GUIDE
GUIDE
GUIDE
GUIDE
guide
guide to