This issue is a somewhat a continuation of #769 .
Say I've got a normal fragment,
class AddressFragment : Fragment() { ... params are fetched on init }
and a view that will use more tha one fragment of this type (ReactiveView is a subclass View with an additional method onEvent from the library GreenBus):
class ServiceDetailView() : ReactiveView(title) {
...
val startAddressFragment : AddressFragment by inject(params = mapOf("p1" to p1v, "p2" to p2v))
... 2 more of this same defin.
}
This code gives the error (on IDEA) that my Fragments are not a subtype of ScopedInstance!
Specifically, the error given is
Error:(27, 51) Kotlin: Type parameter bound for T in inline fun <reified T : Component> inject(overrideScope: Scope = ..., params: Map<String, Any?>? = ...): ReadOnlyProperty<Component, T> where T : ScopedInstance is not satisfied: inferred type AddressFragment is not a subtype of ScopedInstance
for the call
val startAddressFragment : AddressFragment by inject(params = mapOf("addressModel" to serviceModel.startAddress, "label" to "Partida"))
Any lights on the matter? Sadly, having a reference to the fragment is central to my code structure. So I cannot add<AddressFragment>(params...) and lose reference of the created fragment, even though this one works.
All the best.
Hi,
This code creates two Fragment instances and adds them to a View. Each Fragment's data can be set through binding rather than parameter passing. I'm using the Fragment references in an action handler but you can move the vals to be class member variables too.
````
class AddressFragment : Fragment() {
val street = SimpleStringProperty()
override val root = vbox {
label("Street")
textfield(street)
spacing = 2.0
}
}
class OrderView : View("Order View") {
override val root = vbox {
label("BILLING INFO")
val billingInfo = find<AddressFragment>()
add(billingInfo)
label("MAILING INFO")
val mailingInfo = find<AddressFragment>()
add(mailingInfo)
separator()
button("Auto Fill") {
action {
billingInfo.street.value = "123 Main St."
mailingInfo.street.value = "2 Pine Rd."
}
}
padding = Insets(10.0)
spacing = 4.0
}
}
Thanks @bekwam ! Always saving our days. I just wan to point out that it is not possible to move out the val declaration to be a member variable of the View, I successfully used your approach, but having made the fragments a lateinit vars. The error given to me is
Captured member values initialization is forbidden due to possible reassignment.
I guess at least I got halfway across the problems unscratched. If there is someway to make the fragments vals, that would be most perfect!
You can move the variables into the class like this.
````
class OrderView : View("Order View") {
val billingInfo = find<AddressFragment>()
val mailingInfo = find<AddressFragment>()
override val root = vbox {
label("BILLING INFO")
add(billingInfo)
label("MAILING INFO")
add(mailingInfo)
separator()
button("Auto Fill") {
action {
billingInfo.street.value = "123 Main St."
mailingInfo.street.value = "2 Pine Rd."
}
}
padding = Insets(10.0)
spacing = 4.0
}
}
For some reason when I tired this earlier it complained about a getter of something, althoug everythign works now. Thanks a lot, @bekwam ! I think can be closed with honors.
Hang on :) This is not the way to go. You should never need to access a specific fragment instance to change member values like this. Instead you should communicate with injected models, and never reference UI elements in other fragments directly. This creates a strong coupling between ui elements and will most likely come back to bite you later. Learn about scopes and viewmodels and change the state of your models instead of accessing properties in uicomponents directly.
By the way, I forgot that we removed the ability to inject fragments a while back, because it was causing confusion. When you injected a fragment multiple times you'd get a new instance, due to the nature of Fragment. This was by design, but arguably confusing.
Thanks for the tips, @edvin ! I am actually trying as hard as possible to separate UI from Logic code. I'm just not using the viewmodels of TFX because much of the client-side logic code of the TFX app is shared with an android app (cool, right?), hence some stuff that could save up some dev time for me cannot be used simply because of that. I'll try to see if there are easy (and fast) ways to use ItemViewModels with my PO'K'Os. As a matter of fact, I try to make the UI components as "just render and nothing else" as possible, even using the GreenBot EventBus library on both Android and TFX for that.
Anyways, thanks for the info, man! Seriously. And for the error help, of course.