-
FEATURED COMPONENTS
First time here? Check out the FAQ!
[Here Description (question is at the end)]
I've a lot of problem with complicate combobox chaining in my project so I give it a simple POC to allow me to understand it better from the basic. And then I found one behavior which perhaps be by design intentionally but it does not make sense to me. So I post what I found here. What I did is creating this ZUL
<zk> <vlayout viewModel="@id('vm') @init('TestVm')"> LEVEL 1 <combobox selectedItem="@bind(vm.level1)" model="@load(vm.level1Options)"/> LEVEL 2 <combobox selectedItem="@bind(vm.level2)" model="@load(vm.level2Options)"/> </vlayout> </zk>
The TestVM look like this (It's in Kotlin but I hope it is not to understand what is what in each line)
// This one work perfectly class TestVm { var level1: String? = null set(value) { field = value level2 = null } var level2: String? = null @DependsOn("level1") get @Immutable fun getLevel1Options(): List<String> = listOf("A", "B", "C") @DependsOn("level1") fun getLevel2Options(): List<String> = when (level1) { null -> emptyList() else -> (1..3).map { "${level1}-${it}" } } }
This chained drop down work as expected in this very simple scenario.
The problem come after this. I think of the scenario when level2 is not an immediate property in VM but a nested property in some complex object like "level2.nested1.nested2.nested3". In such case I sometime may not have access to the source code to add annotation to the getter of "level2.nested1.nested2.nested3" so the alternative way is to use @NotifyChange at the setter of what it depends on, for this example it's "level1". So I change my code to this
class TestVm { var level1: String? = null @NotifyChange("level2") // It will work perfectly if I change it to @NotifyChange("level2", "level2Options") set(value) { field = value level2 = null } var level2: String? = null @Immutable fun getLevel1Options(): List<String> = listOf("A", "B", "C") @DependsOn("level1") // This line has no effect, I can remove it fun getLevel2Options(): List<String> = when (level1) { null -> emptyList() else -> (1..3).map { "${level1}-${it}" } } }
Here it does not work like before. When level1 is changed, it only notify change of level2. But not for "getLevel2Options()". It's obvious that the @DependsOn("level1") annotated to "getLevel2Options()" is being ignored!!!
Base on my guessing, I try and am successful on solving this problem by changing the annotation at setter of level1 from @NotifyChange("level2")
to @NotifyChange("level2", "level2Options")
. Of course, I can remove @DependsOn("level1")
from "getLevel2Options()" without affecting anything.
But I cannot afford to apply this solution in all situation. It is not practical to let the setter of level1 know every expression that want to depend on it. Also, it's hard to maintain.
[Here Question 1]
I wonder why ZK does not just, when level1 is changed, notify change of properties both those that specified using @NotifyChange and those that specified using @DependsOn.
I may just don't know it much enough or miss some important point. If it's the case, please lighten me up on this.
Thank you in advance for everybody's kind answers.
=====Update more information while waiting for the answer to question above=====
There's one important thing I forgot. While nested property using dot-notation is possible in EL expression, it is not supported in @NotifyChange and @DependsOn. So this does not work (now Java)
ZUL
<label value="@load(vm.family.father.name)"/>
VM
@NotifyChange("family.father.name") @Command public void assignFatherName(String name) { this.family.father.name = name }
I cannot just put the long property path in @NotifyChange and wait for change to appear in the label component. What I have to do is
@Command public void assignFatherName(String name) { this.family.father.name = name BindUtils.postNotifyChange(null, null, this.family.father, "name"); }
It seems there's a good reason that dot-notation is not supported in @NotifyChange and @DependsOn (Please correct me if I'm wrong). If it does support, it would reduce a lot of boiler plate code.
Another finding
When I have this in my VM
var test2: String? = null @DependsOn("test1") get
And I do this in VM
BindUtils.postNotifyChange(null, null, this, "test1")
All component that bind to "test1" will get updated. But not components that bind to "test2".
[Here Question 2]
Should I expect that the change notifications be chained based on dependency defined in @DependsOn ?
Asked: 2017-04-06 08:03:31 +0800
Seen: 33 times
Last updated: Apr 06 '17
zkspringmvc jar licence is GPL ?
Build web application without any zul files
Custom component that extends Textbox does not fire onChange event
java.lang.NullPointerException to update to zk 8.0.1
"Spring Session" + ZK + "Spring core" @Listen method refresh the screen
zk8 client side binding to a viewmodel command seems not to work
upload event dialog do not open in browser
Notification is not shown inside sticky block
Where can I find documentation (like ZK Developer's Reference) for ZK 8.0.2.2 ?