I have 2 data classes and an ItemViewModel, e.g.
data class User(val user: UserObject) {
val nameProperty = SimpleStringProperty(user.name)
var name by nameProperty
val groupProperty = SimpleObjectProperty<Group>(Group(user.group))
var group by groupProperty
}
data class Group(val group: GroupObject) {
val nameProperty = SimpleStringProperty(group.name)
var name by nameProperty
}
class UserModel : ItemViewModel<User>() {
val name = bind(User::nameProperty)
}
How I can describe an ItemViewModel so I can bind user.group.name and change it on the UI side?
Hmm, I think I should:
GroupModelval group = GroupModel() inside my UserModelUserModel.rebindOnChange I should just set group.item = Group(...)It works but perhaps there's a better way?
UPD:
Looks like doing UserModel.group.commit() (UserModel.group is a GroupModel : ItemViewModel() instance that's bind to User.group) writes to the User.groupProperty and that's basically what I want. Closing.
Agreed. By the way, data classes is not really buying you anything here, better to not declare your domain objects as data classes IMO.
Should I simply declare them as classes then?
Yes. Out of curiosity, what did you hope to gain by declaring them as data classes?
I thought since I hold data in these classes, I should use data classes for this purpose.
Data classes can save you some time and code if you have immutable objects and need some or more of the features described here:
https://kotlinlang.org/docs/reference/data-classes.html
Since JavaFX based properties are not immutable, and since the equals, hashCode, toString, copy and other "automatic" features of a data class would not work as expected, it makes little sense to declare them as data classes IMO :)
Okay, thanks for the tip :) I'll change my data classes to simple classes then.
Perhaps I have just turned my brain off and it's something stupidly easy but how should I do it?, I want to store File object in my ItemViewModel, for example:
import javafx.beans.property.SimpleObjectProperty
import tornadofx.ItemViewModel
import java.io.File
class User(icon: File? = null) {
val iconProperty = SimpleObjectProperty(this, "icon", icon)
}
class UserModel(user: User) : ItemViewModel<User>(user) {
val icon = bind(User::iconProperty)
}
val userModel = UserModel(User(File("...")))
println(userModel.icon.value.value) // This is not right is it?
that syntax for accessing the file just doesn't feel right, or is there something I'm overlooking?
This is a quirk you hit because you've implicitly declared the SimpleObjectProperty type as File? and we don't have bind overloads for nullable observable types. That might seem strange, but you actually don't need them, your properties can still contain null.
Bottom line, declare your iconProperty like this:
val iconProperty = SimpleObjectProperty<File>(this, "icon", icon)
}
And now you can access the value inside the usermodel like this:
userModel.icon.value
I don't remember if we have tried to add bind overloads for nullable observable property types, we might want to try that again.
Sorry for the late response, that worked nicely, worth mentioning that the field holding the bound property should be defined as
val icon: Property<File?> = bind(...)
so that we won't face problems with platform types.
(also why it returns platform type instead of nullable type? seems unsafe..)
aside from that, it's perfect, thanks for the help! :-)