-
Type:
Bug
-
Resolution: Unresolved
-
Priority:
Normal
-
None
-
Affects Version/s: 9.6.4
-
Component/s: Components
-
Security Level: Jimmy
-
None
Steps to Reproduce
run this example
<zk> <combobox instantSelect="false" autodrop="true" autocomplete="true" onChanging='Clients.log(event.name + ": " + event.value)' onSelect='Clients.log(event.name + ": " + (self.selectedItem == null ? null : self.selectedItem.value))'> <comboitem value="Authorize" label="${self.value}"/> <comboitem value="Alpha" label="${self.value}"/> <comboitem value="Beta" label="${self.value}"/> <comboitem value="Beer" label="${self.value}"/> <comboitem value="Beef" label="${self.value}"/> </combobox> </zk>
Type "a" in the input field
Wait a few seconds to make onChanging is complete.
Type "ctrl" and release "ctrl" without making changes to the input value (or other non-character keys such as ctrl, alt, num lock. etc)
Current Result
Pressing a releasing a key causes typeAhead to trigger.
Pressing a releasing "a" cause onChanging value to be sent
onChanging: a
pressing and releasing "ctrl" causes typeAhead to trigger again, but uses the current already autocompleted value "authorize" as the input value, which in turns causes
onChanging: authorize
Note:
A different outcome of the same effect also happen if multiple character keys are pressed in sequence
For example, the sequence
Keydown: A
Keydown: U
KeyUp: A
KeyUp: U
will trigger 2 typeAhead invocations on the input when the content of the input is already "au"
The first invocation will autocomplete the input to "authorize" and send onchanging: au
the 2nd invocation will not trigger while the input value is already "authorize" and will send onchanging: authorize
Expected Result
OnChanging shouldn't trigger inconsistently when multiple keyUp events are resolved in sequence if the actual typed value didn't change in between.
Debug Information
doKeyUp_ will fire _typeahead
typeahead will store the last human-typed value into this.valueEnter_
the first invocation of typeahead stores the actual human-typed value in this.valueEnter_, then set the input value to the autocomplete string
the 2nd invocation of typeahead uses the autocomplete value currently in the input as the last human-typed value incorrectly and stores it into this.valueEnter_
When onChanging triggers, it reads the this.valueEnter_, which currently holds the autocompleted value instead of the last human-typed value.
Workaround
partial workaround: counts concurrently pressed keys, and only fire keyUp once no keys are currently held.
This prevents multiple typeAheads being sent during rapid typing, but doesn't prevent typeahead on already autocompleted value when pressing non-character keys like ctrl, alt, num lock. etc
<script><![CDATA[ zk.afterLoad("zul.inp", function () { var _xCombobox = {}; zk.override(zul.inp.Combobox.prototype, _xCombobox, { doKeyDown_: function doKeyDown_(evt) { if(!this.keys){ this.keys = new Map(); } this.keys.set(evt.key, true); if (!this._disabled) { this._doKeyDown(evt); if (!evt.stopped) this.$supers('doKeyDown_', arguments); } }, doKeyUp_: function doKeyUp_(evt) { this.keys.delete(evt.key) if (!this._disabled && !this.keys.size) { if (!this._readonly && !this._autoCompleteSuppressed) { var keyCode = evt.keyCode, bDel = keyCode == 8 /*BS*/ || keyCode == 46; /*DEL*/ // ZK-3607: The value is not ready in onKeyDown, but is ready in onKeyUp this._typeahead(bDel); } this.$supers('doKeyUp_', arguments); } } }); }); ]]></script>