@@ -822,36 +822,52 @@ LovDropdown.prototype.renderResults = function (searchText, filterCriteria, sele
822
822
renderPromiseReject = reject ;
823
823
} ) ;
824
824
825
+ var retPromise = new Promise ( function ( resolve , reject ) {
826
+ renderPromise . then ( function ( ) {
827
+ // wait until the changes propagate to the collection and the collection handles the DP
828
+ // refresh event due to filter criteria changing before resolving the promise
829
+ var busyContext = Context . getContext ( this . _containerElem [ 0 ] ) . getBusyContext ( ) ;
830
+ busyContext . whenReady ( ) . then ( resolve , reject ) ;
831
+ } . bind ( this ) , reject ) ;
832
+ } . bind ( this ) ) ;
833
+ // save the most recent promise so we can ignore old responses
834
+ this . _lastRenderResultsPromise = retPromise ;
835
+
825
836
var collectionContext = this . _collectionContext ;
826
837
collectionContext . data = this . _dataProvider ;
827
838
collectionContext . searchText = searchText ;
828
839
collectionContext . selected = new ojkeyset . KeySetImpl ( [ selectedValue ] ) ;
840
+
841
+ // JET-34871 - FILTERING DANGLING BUSY STATE
842
+ // if there is an existing, unresolved renderPromise, reject it now so that we don't end up with
843
+ // orphaned busy states
844
+ if ( collectionContext . renderError ) {
845
+ var contextRenderError = collectionContext . renderError ;
846
+ this . _clearContextRenderPromiseFunctions ( collectionContext ) ;
847
+ contextRenderError ( 'LovDropdown.renderResults: rejecting earlier promise' ) ;
848
+ }
829
849
collectionContext . renderDone = renderPromiseResolve ;
830
850
collectionContext . renderError = renderPromiseReject ;
831
851
832
852
this . _collectionRendererFunc ( collectionContext ) ;
833
853
834
854
var afterRetPromiseFunc = function ( ) {
835
- this . _duringListViewInitialization = false ;
855
+ // ignore old responses
856
+ if ( retPromise === this . _lastRenderResultsPromise ) {
857
+ this . _duringListViewInitialization = false ;
858
+ }
836
859
resolveBusyState ( ) ;
837
860
} . bind ( this ) ;
838
861
839
- var retPromise = new Promise ( function ( resolve , reject ) {
840
- renderPromise . then ( function ( ) {
841
- // wait until the changes propagate to the collection and the collection handles the DP
842
- // refresh event due to filter criteria changing before resolving the promise
843
- var busyContext = Context . getContext ( this . _containerElem [ 0 ] ) . getBusyContext ( ) ;
844
- busyContext . whenReady ( ) . then ( resolve , reject ) ;
845
- } . bind ( this ) , reject ) ;
846
- } . bind ( this ) ) ;
847
-
848
862
return retPromise . then ( function ( ) {
849
863
afterRetPromiseFunc ( ) ;
850
864
} , function ( reason ) {
851
- Logger . warn (
852
- 'Select: LovDropdown.renderResults retPromise rejected: ' + reason ) ;
865
+ // ignore old responses
866
+ if ( retPromise === this . _lastRenderResultsPromise ) {
867
+ Logger . warn ( 'Select: LovDropdown.renderResults retPromise rejected: ' + reason ) ;
868
+ }
853
869
afterRetPromiseFunc ( ) ;
854
- } ) ;
870
+ } . bind ( this ) ) ;
855
871
} ;
856
872
857
873
LovDropdown . prototype . updateLabel = function ( ariaLabelId , ariaLabel ) {
@@ -867,9 +883,18 @@ LovDropdown.prototype.updateLabel = function (ariaLabelId, ariaLabel) {
867
883
}
868
884
} ;
869
885
886
+ LovDropdown . prototype . _clearContextRenderPromiseFunctions = function ( context ) {
887
+ // eslint-disable-next-line no-param-reassign
888
+ context . renderDone = null ;
889
+ // eslint-disable-next-line no-param-reassign
890
+ context . renderError = null ;
891
+ } ;
892
+
870
893
LovDropdown . prototype . _defaultCollectionRenderer = function ( context ) {
871
894
var listView ;
872
895
var busyContext ;
896
+ var contextRenderDone = context . renderDone ;
897
+ var contextRenderError = context . renderError ;
873
898
if ( ! this . _resultsElem ) {
874
899
var $parentElem = $ ( context . parentElement ) ;
875
900
var placeholderElem = $parentElem . find ( '.oj-searchselect-results-placeholder' ) [ 0 ] ;
@@ -925,21 +950,25 @@ LovDropdown.prototype._defaultCollectionRenderer = function (context) {
925
950
if ( this . _itemTemplate ) {
926
951
this . _getTemplateEngineFunc ( ) . then ( function ( templateEngine ) {
927
952
listView . setProperty ( 'item.renderer' , this . _templateItemRenderer . bind ( this , templateEngine ) ) ;
928
- context . renderDone ( ) ;
953
+ this . _clearContextRenderPromiseFunctions ( context ) ;
954
+ contextRenderDone ( ) ;
929
955
} . bind ( this ) , function ( reason ) {
930
956
Logger . warn (
931
957
'Select: template item renderer template engine promise rejected: ' + reason ) ;
932
- context . renderError ( reason ) ;
933
- } ) ;
958
+ this . _clearContextRenderPromiseFunctions ( context ) ;
959
+ contextRenderError ( reason ) ;
960
+ } . bind ( this ) ) ;
934
961
} else {
935
962
listView . setProperty ( 'item.renderer' , this . _defaultItemRenderer . bind ( this ) ) ;
936
- context . renderDone ( ) ;
963
+ this . _clearContextRenderPromiseFunctions ( context ) ;
964
+ contextRenderDone ( ) ;
937
965
}
938
966
} . bind ( this ) , function ( reason ) {
939
967
Logger . warn (
940
968
'Select: creating default listView busyContext promise rejected: ' + reason ) ;
941
- context . renderError ( reason ) ;
942
- } ) ;
969
+ this . _clearContextRenderPromiseFunctions ( context ) ;
970
+ contextRenderError ( reason ) ;
971
+ } . bind ( this ) ) ;
943
972
} else {
944
973
listView = this . _resultsElem [ 0 ] ;
945
974
// Need to wait until _SetupResources is called asynchronously on listView so that when we
@@ -949,16 +978,20 @@ LovDropdown.prototype._defaultCollectionRenderer = function (context) {
949
978
busyContext . whenReady ( ) . then ( function ( ) {
950
979
listView . data = context . data ;
951
980
listView . selected = context . selected ;
952
- context . renderDone ( ) ;
953
- } , function ( reason ) {
981
+ this . _clearContextRenderPromiseFunctions ( context ) ;
982
+ contextRenderDone ( ) ;
983
+ } . bind ( this ) , function ( reason ) {
954
984
Logger . warn (
955
985
'Select: busyContext promise rejected before setting props on listView: ' + reason ) ;
956
- context . renderError ( reason ) ;
957
- } ) ;
986
+ this . _clearContextRenderPromiseFunctions ( context ) ;
987
+ contextRenderError ( reason ) ;
988
+ } . bind ( this ) ) ;
958
989
}
959
990
} ;
960
991
961
992
LovDropdown . prototype . _templateCollectionRenderer = function ( context ) {
993
+ var contextRenderDone = context . renderDone ;
994
+ var contextRenderError = context . renderError ;
962
995
if ( ! this . _resultsElem ) {
963
996
var $parentElem = $ ( context . parentElement ) ;
964
997
var placeholderElem = $parentElem . find ( '.oj-searchselect-results-placeholder' ) [ 0 ] ;
@@ -975,18 +1008,21 @@ LovDropdown.prototype._templateCollectionRenderer = function (context) {
975
1008
placeholderElem . parentNode . removeChild ( placeholderElem ) ;
976
1009
this . _resultsElem = $parentElem . find ( '.oj-select-results' ) ; // '.oj-listbox-results'
977
1010
this . _resultsElem . on ( 'click' , LovUtils . killEvent ) ;
978
- context . renderDone ( ) ;
1011
+ this . _clearContextRenderPromiseFunctions ( context ) ;
1012
+ contextRenderDone ( ) ;
979
1013
} . bind ( this ) , function ( reason ) {
980
1014
Logger . warn (
981
1015
'Select: template collection renderer template engine promise rejected: ' + reason ) ;
982
- context . renderError ( reason ) ;
983
- } ) ;
1016
+ this . _clearContextRenderPromiseFunctions ( context ) ;
1017
+ contextRenderError ( reason ) ;
1018
+ } . bind ( this ) ) ;
984
1019
} else {
985
1020
var templateContext = this . _collectionTemplateContext ;
986
1021
templateContext . data = context . data ;
987
1022
templateContext . searchText = context . searchText ;
988
1023
templateContext . selected = context . selected ;
989
- context . renderDone ( ) ;
1024
+ this . _clearContextRenderPromiseFunctions ( context ) ;
1025
+ contextRenderDone ( ) ;
990
1026
}
991
1027
} ;
992
1028
@@ -1759,7 +1795,7 @@ var AbstractLovBase = function (options) {
1759
1795
this . _showMainFieldFunc = options . showMainFieldFunc ;
1760
1796
this . _setFilterFieldTextFunc = options . setFilterFieldTextFunc ;
1761
1797
1762
- this . _queryCount = 0 ;
1798
+ this . _lastDataProviderPromise = null ;
1763
1799
1764
1800
// support ko options-binding
1765
1801
// init dataProvider fetchType
@@ -2031,9 +2067,6 @@ AbstractLovBase.prototype.updateResults = function (initial, focusFirstElem) {
2031
2067
2032
2068
AbstractLovBase . prototype . _runQuery = function ( initial , term , focusFirstElem ) {
2033
2069
var lovDropdown = this . _lovDropdown ;
2034
- var self = this ;
2035
- // sequence number used to drop out-of-order responses
2036
- var queryNumber = 0 ;
2037
2070
2038
2071
if ( this . _minLength > term . length ) {
2039
2072
this . closeDropdown ( ) ;
@@ -2042,9 +2075,6 @@ AbstractLovBase.prototype._runQuery = function (initial, term, focusFirstElem) {
2042
2075
2043
2076
this . openDropdown ( true ) ;
2044
2077
2045
- this . _queryCount += 1 ;
2046
- queryNumber = this . _queryCount ;
2047
-
2048
2078
// lovDropdown.clearHighlight();
2049
2079
if ( ! ( term !== undefined && term !== null && ( initial !== true || this . _minLength > 0 ) ) ) {
2050
2080
// eslint-disable-next-line no-param-reassign
@@ -2066,20 +2096,21 @@ AbstractLovBase.prototype._runQuery = function (initial, term, focusFirstElem) {
2066
2096
// lovDropdown.setSearchText(term);
2067
2097
var fetchPromise = this . _fetchFromDataProvider ( term ) ;
2068
2098
fetchPromise . then ( function ( ) {
2069
- self . _handleQueryResultsFetch ( queryNumber ) ;
2070
- } , function ( reason ) {
2071
- Logger . warn ( 'Select: _fetchFromDataProvider promise was rejected: ' + reason ) ;
2072
- self . _handleQueryResultsFetch ( queryNumber ) ;
2073
- } ) ;
2099
+ // ignore old responses
2100
+ if ( fetchPromise === this . _lastDataProviderPromise ) {
2101
+ this . _handleQueryResultsFetch ( ) ;
2102
+ }
2103
+ } . bind ( this ) , function ( reason ) {
2104
+ // ignore old responses
2105
+ if ( fetchPromise === this . _lastDataProviderPromise ) {
2106
+ Logger . warn ( 'Select: _fetchFromDataProvider promise was rejected: ' + reason ) ;
2107
+ this . _handleQueryResultsFetch ( ) ;
2108
+ }
2109
+ } . bind ( this ) ) ;
2074
2110
}
2075
2111
} ;
2076
2112
2077
- AbstractLovBase . prototype . _handleQueryResultsFetch = function ( queryNumber ) {
2078
- // ignore old responses
2079
- if ( queryNumber !== this . _queryCount ) {
2080
- return ;
2081
- }
2082
-
2113
+ AbstractLovBase . prototype . _handleQueryResultsFetch = function ( ) {
2083
2114
// ignore a response if the oj-combobox has been closed before it was received
2084
2115
if ( ! this . isDropdownOpen ( ) ) {
2085
2116
return ;
@@ -2160,7 +2191,7 @@ AbstractLovBase.prototype._fetchFromDataProvider = function (term) {
2160
2191
filterCriteria = oj . FilterFactory . getFilter ( { filterDef : { text : term } } ) ;
2161
2192
}
2162
2193
2163
- var retPromise = new Promise ( function ( resolve ) {
2194
+ var retPromise = new Promise ( function ( resolve , reject ) {
2164
2195
// fetch data from dataProvider
2165
2196
var renderPromise = this . _lovDropdown . renderResults ( term , filterCriteria ,
2166
2197
LovUtils . isValueForPlaceholder ( this . _value ) ? null : this . _value ) ;
@@ -2171,17 +2202,25 @@ AbstractLovBase.prototype._fetchFromDataProvider = function (term) {
2171
2202
}
2172
2203
2173
2204
// clear busy context
2174
- fetchResolveFunc ( ) ;
2175
-
2176
- resolve ( ) ;
2205
+ fetchResolveFunc ( ) ; // ignore old responses
2206
+ if ( retPromise === this . _lastDataProviderPromise ) {
2207
+ resolve ( ) ;
2208
+ } else {
2209
+ reject ( 'AbstractLovBase._fetchFromDataProvider: rejecting earlier promise' ) ;
2210
+ }
2177
2211
} . bind ( this ) ;
2178
2212
renderPromise . then ( function ( ) {
2179
2213
afterRenderPromiseFunc ( ) ;
2180
2214
} , function ( reason ) {
2181
- Logger . warn ( 'Select: renderResults promise was rejected: ' + reason ) ;
2215
+ // ignore old responses
2216
+ if ( retPromise === this . _lastDataProviderPromise ) {
2217
+ Logger . warn ( 'Select: renderResults promise was rejected: ' + reason ) ;
2218
+ }
2182
2219
afterRenderPromiseFunc ( ) ;
2183
2220
} ) ;
2184
2221
} . bind ( this ) ) ;
2222
+ // save the most recent promise so we can ignore old data provider responses
2223
+ this . _lastDataProviderPromise = retPromise ;
2185
2224
return retPromise ;
2186
2225
} ;
2187
2226
@@ -3987,6 +4026,22 @@ oj.__registerWidget('oj.ojSelect2', $.oj.editableValue, {
3987
4026
return returnValue ;
3988
4027
} ,
3989
4028
4029
+ /**
4030
+ * @override
4031
+ * @protected
4032
+ * @memberof ! oj.ojSelect2
4033
+ */
4034
+ _SetValue : function ( newValue , event , options ) {
4035
+ var displayValue = this . _GetDisplayValue ( ) ;
4036
+ if ( newValue === displayValue ) {
4037
+ // we don't want to set the displayValue as the value, so if the newValue being set matches
4038
+ // the displayValue, use the currently set value instead
4039
+ // eslint-disable-next-line no-param-reassign
4040
+ newValue = this . options . value ;
4041
+ }
4042
+ return this . _super ( newValue , event , options ) ;
4043
+ } ,
4044
+
3990
4045
/**
3991
4046
* @override
3992
4047
* @protected
0 commit comments