Closed SKeeneCode closed 4 years ago
class ModelVView : ItemViewModel {
override fun onCommit() {}
}
there is also a change state property (dirty
), it will become false after a commit
Thanks @SchweinchenFuntik - I already use the above to save config settings, but it means if I want to react to the change outside the ItemViewModel, (such as in a view) I would need to do something like:
class ModelVView : ItemViewModel { val showGrid = bind(Model::booleanProperty) val showGridWasComitted = property(false) override fun onCommit() { showGridWasComitted.value = !showGridWasComitted } }
and then bind to showGridWasComitted
in the view. I really want to avoid the need to create another property for every single setting.
I got a little close with using the dirtyStateFor:
grid().visibleWhen { BooleanBinding.booleanExpression(settings.showGrid) .and(settings.dirtyStateFor(PageSettingsViewModel::showGrid).not()) }
But this doesn't quite behave as I would like.
Reading again into the docs, it looks like I need a way to bind to the backing property created by the ItemViewModel when bind is used, not the facade property.
From the docs:
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.
There seems to be a method to get the backing value, but not the backing property, is there a way to access it? I would love to avoid the solution above to double the size of my view model...
Do you want to bind the show Grid property of the model and not the ViewModel? Or when the values of the model and ViewModel are different?
val model = NamedModel()
val bindValueDirty = booleanBinding(model.value, model.itemProperty) { value != model.item.value }
class Named() {
val nameProperty = SimpleStringProperty()
var name by nameProperty
val valueProperty = SimpleIntegerProperty()
var value by valueProperty
}
class NamedModel : ItemViewModel<Named>() {
val name = bind(Named::nameProperty)
val value = bind(Named::valueProperty)
}
I had actually forgot about binding to just the model and not the view model. I've had it drilled into my head that only the view model should communicate in anyway with the model and the view should bind only to the view model. Was I mistaken?
I am using the config example from the guide here. My view model declares its properties in a similar fashion:
val showGrid = bind { SimpleBooleanProperty(item?.drawGrid, "", config.boolean(CONFIG_SHOW_GRID) ?: false) }
The problem is item?.drawGrid
is a plain Boolean
meaning I can't bind directly to it. I need to declare the SimpleBooleanProperty
in a place where I have access to config
so I can set its initial value. I suppose I could pass it down as a parameter? I wonder if there is an easier way :/
I` had actually forgot about binding to just the model and not the view model. I've had it drilled into my head that only the view model should communicate in anyway with the model and the view should bind only to the view model. Was I mistaken?
this is a public API - you can use it, of course you can make a property inside the ViewModel, but this error seems to me just the same, since you are making a special case public. But do not abuse such bindings
The problem is item?.drawGrid is a plain Boolean meaning I can't bind directly to it. I need to declare the SimpleBooleanProperty in a place where I have access to config so I can set its initial value. I suppose I could pass it down as a parameter? I wonder if there is an easier way :/
it doesn’t matter, you get attached to the itemProperty property and compare the values already, and it doesn’t matter whether they are stored in the JavaFX properties or kotlin properties
class Named() {
val nameProperty = SimpleStringProperty()
var name by nameProperty
val valueProperty = SimpleIntegerProperty()
var value by valueProperty
var showGrid: Boolean = false
}
class NamedModel : ItemViewModel<Named>() {
val name = bind(Named::nameProperty)
val value = bind(Named::valueProperty)
val showGrid = bind(Named::showGrid)
}
class TestView() : View("My View") {
val model = NamedModel()
val bind = booleanBinding(model.value, model.itemProperty) { value != model.item.value }
val bindShowGrid = booleanBinding(model.showGrid, model.itemProperty) { value != model.item.showGrid }
override val root = vbox { }
}
bindShowGrid - will be updated only when model.showGrid
is updated or when item changes (property of model.itemProperty
changes)
Nice explanation and example, thanks for once again taking time to help me out. I learn a little more with every question :)
I'm trying to create some application settings for my users. In my example I have a grid I want the user to be able to toggle visibility via a settings window. I have a checkbox binded to a boolean property in a view model:
val showGrid = bind { SimpleBooleanProperty(item?.drawGrid, "", config.boolean(CONFIG_SHOW_GRID) ?: false) }
There is a save button which is enabled when the model is dirty and it calls
commit()
.Elsewhere I'm trying to react to these changes. If I do:
grid.visibleWhen(settings.showGrid)
This runs as soon as the value is changed, regardless of whether the change has been committed to the underlying model or not.
How can I react to a change only when the model is committed?