-
Bug
-
Resolution: Fixed
-
Major
-
8.0.4.1
-
Security Level: Jimmy
-
None
-
None
Steps to Reproduce
run the attached example
click the buttons in order
1.1 "listen" A, B, C, "fire"
1.2 "unlisten" C, B, A , "fire"
2.1 "listen" A, B, C, "fire"
2.2 "unlisten" A, B, C , "fire"
Actual Result
1.1 console shows
onAnyWatch A p1 onAnyWatch B p2 onAnyWatch C p1
1.2 console remains empty (expected)
2.1 again console show the expected listener invocation
onAnyWatch A p1 onAnyWatch B p2 onAnyWatch C p1
2.2 listener A on P1 is still called correctly
onAnyWatch A p1
i.e. it wasn't removed even though unlisten was called
Expected Result
zWatch.unlisten should remove the specified listeners correctly
Root Cause
the mechanisms how listen and unlisten determine where to add/remove a listener don't match
listen: will create duplicate entries for the same widget if another widget has been added for the same bind level inbetween
https://github.com/zkoss/zk/blob/v8.0.4.1/zk/src/archive/web/js/zk/evt.js#L468-L471
unlisten: will only try to remove the listenerinfo from the first element found
there's no check whether or not the $remove function was successful
https://github.com/zkoss/zk/blob/v8.0.4.1/zk/src/archive/web/js/zk/evt.js#L500
Workaround
replace line 500 in evts.js with the below to continue searching for a matching listener if $remove returned false
if(!wts[j][1].$remove(inf)) {continue};
An alternative fix could be to make sure all watch listeners for the same widget are added in a single listener info object during listen, however this will affect the listener invocation order.