@@ -822,36 +822,52 @@ LovDropdown.prototype.renderResults = function (searchText, filterCriteria, sele
822822 renderPromiseReject = reject ;
823823 } ) ;
824824
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+
825836 var collectionContext = this . _collectionContext ;
826837 collectionContext . data = this . _dataProvider ;
827838 collectionContext . searchText = searchText ;
828839 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+ }
829849 collectionContext . renderDone = renderPromiseResolve ;
830850 collectionContext . renderError = renderPromiseReject ;
831851
832852 this . _collectionRendererFunc ( collectionContext ) ;
833853
834854 var afterRetPromiseFunc = function ( ) {
835- this . _duringListViewInitialization = false ;
855+ // ignore old responses
856+ if ( retPromise === this . _lastRenderResultsPromise ) {
857+ this . _duringListViewInitialization = false ;
858+ }
836859 resolveBusyState ( ) ;
837860 } . bind ( this ) ;
838861
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-
848862 return retPromise . then ( function ( ) {
849863 afterRetPromiseFunc ( ) ;
850864 } , 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+ }
853869 afterRetPromiseFunc ( ) ;
854- } ) ;
870+ } . bind ( this ) ) ;
855871} ;
856872
857873LovDropdown . prototype . updateLabel = function ( ariaLabelId , ariaLabel ) {
@@ -867,9 +883,18 @@ LovDropdown.prototype.updateLabel = function (ariaLabelId, ariaLabel) {
867883 }
868884} ;
869885
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+
870893LovDropdown . prototype . _defaultCollectionRenderer = function ( context ) {
871894 var listView ;
872895 var busyContext ;
896+ var contextRenderDone = context . renderDone ;
897+ var contextRenderError = context . renderError ;
873898 if ( ! this . _resultsElem ) {
874899 var $parentElem = $ ( context . parentElement ) ;
875900 var placeholderElem = $parentElem . find ( '.oj-searchselect-results-placeholder' ) [ 0 ] ;
@@ -925,21 +950,25 @@ LovDropdown.prototype._defaultCollectionRenderer = function (context) {
925950 if ( this . _itemTemplate ) {
926951 this . _getTemplateEngineFunc ( ) . then ( function ( templateEngine ) {
927952 listView . setProperty ( 'item.renderer' , this . _templateItemRenderer . bind ( this , templateEngine ) ) ;
928- context . renderDone ( ) ;
953+ this . _clearContextRenderPromiseFunctions ( context ) ;
954+ contextRenderDone ( ) ;
929955 } . bind ( this ) , function ( reason ) {
930956 Logger . warn (
931957 'Select: template item renderer template engine promise rejected: ' + reason ) ;
932- context . renderError ( reason ) ;
933- } ) ;
958+ this . _clearContextRenderPromiseFunctions ( context ) ;
959+ contextRenderError ( reason ) ;
960+ } . bind ( this ) ) ;
934961 } else {
935962 listView . setProperty ( 'item.renderer' , this . _defaultItemRenderer . bind ( this ) ) ;
936- context . renderDone ( ) ;
963+ this . _clearContextRenderPromiseFunctions ( context ) ;
964+ contextRenderDone ( ) ;
937965 }
938966 } . bind ( this ) , function ( reason ) {
939967 Logger . warn (
940968 'Select: creating default listView busyContext promise rejected: ' + reason ) ;
941- context . renderError ( reason ) ;
942- } ) ;
969+ this . _clearContextRenderPromiseFunctions ( context ) ;
970+ contextRenderError ( reason ) ;
971+ } . bind ( this ) ) ;
943972 } else {
944973 listView = this . _resultsElem [ 0 ] ;
945974 // Need to wait until _SetupResources is called asynchronously on listView so that when we
@@ -949,16 +978,20 @@ LovDropdown.prototype._defaultCollectionRenderer = function (context) {
949978 busyContext . whenReady ( ) . then ( function ( ) {
950979 listView . data = context . data ;
951980 listView . selected = context . selected ;
952- context . renderDone ( ) ;
953- } , function ( reason ) {
981+ this . _clearContextRenderPromiseFunctions ( context ) ;
982+ contextRenderDone ( ) ;
983+ } . bind ( this ) , function ( reason ) {
954984 Logger . warn (
955985 '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 ) ) ;
958989 }
959990} ;
960991
961992LovDropdown . prototype . _templateCollectionRenderer = function ( context ) {
993+ var contextRenderDone = context . renderDone ;
994+ var contextRenderError = context . renderError ;
962995 if ( ! this . _resultsElem ) {
963996 var $parentElem = $ ( context . parentElement ) ;
964997 var placeholderElem = $parentElem . find ( '.oj-searchselect-results-placeholder' ) [ 0 ] ;
@@ -975,18 +1008,21 @@ LovDropdown.prototype._templateCollectionRenderer = function (context) {
9751008 placeholderElem . parentNode . removeChild ( placeholderElem ) ;
9761009 this . _resultsElem = $parentElem . find ( '.oj-select-results' ) ; // '.oj-listbox-results'
9771010 this . _resultsElem . on ( 'click' , LovUtils . killEvent ) ;
978- context . renderDone ( ) ;
1011+ this . _clearContextRenderPromiseFunctions ( context ) ;
1012+ contextRenderDone ( ) ;
9791013 } . bind ( this ) , function ( reason ) {
9801014 Logger . warn (
9811015 'Select: template collection renderer template engine promise rejected: ' + reason ) ;
982- context . renderError ( reason ) ;
983- } ) ;
1016+ this . _clearContextRenderPromiseFunctions ( context ) ;
1017+ contextRenderError ( reason ) ;
1018+ } . bind ( this ) ) ;
9841019 } else {
9851020 var templateContext = this . _collectionTemplateContext ;
9861021 templateContext . data = context . data ;
9871022 templateContext . searchText = context . searchText ;
9881023 templateContext . selected = context . selected ;
989- context . renderDone ( ) ;
1024+ this . _clearContextRenderPromiseFunctions ( context ) ;
1025+ contextRenderDone ( ) ;
9901026 }
9911027} ;
9921028
@@ -1759,7 +1795,7 @@ var AbstractLovBase = function (options) {
17591795 this . _showMainFieldFunc = options . showMainFieldFunc ;
17601796 this . _setFilterFieldTextFunc = options . setFilterFieldTextFunc ;
17611797
1762- this . _queryCount = 0 ;
1798+ this . _lastDataProviderPromise = null ;
17631799
17641800 // support ko options-binding
17651801 // init dataProvider fetchType
@@ -2031,9 +2067,6 @@ AbstractLovBase.prototype.updateResults = function (initial, focusFirstElem) {
20312067
20322068AbstractLovBase . prototype . _runQuery = function ( initial , term , focusFirstElem ) {
20332069 var lovDropdown = this . _lovDropdown ;
2034- var self = this ;
2035- // sequence number used to drop out-of-order responses
2036- var queryNumber = 0 ;
20372070
20382071 if ( this . _minLength > term . length ) {
20392072 this . closeDropdown ( ) ;
@@ -2042,9 +2075,6 @@ AbstractLovBase.prototype._runQuery = function (initial, term, focusFirstElem) {
20422075
20432076 this . openDropdown ( true ) ;
20442077
2045- this . _queryCount += 1 ;
2046- queryNumber = this . _queryCount ;
2047-
20482078 // lovDropdown.clearHighlight();
20492079 if ( ! ( term !== undefined && term !== null && ( initial !== true || this . _minLength > 0 ) ) ) {
20502080 // eslint-disable-next-line no-param-reassign
@@ -2066,20 +2096,21 @@ AbstractLovBase.prototype._runQuery = function (initial, term, focusFirstElem) {
20662096 // lovDropdown.setSearchText(term);
20672097 var fetchPromise = this . _fetchFromDataProvider ( term ) ;
20682098 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 ) ) ;
20742110 }
20752111} ;
20762112
2077- AbstractLovBase . prototype . _handleQueryResultsFetch = function ( queryNumber ) {
2078- // ignore old responses
2079- if ( queryNumber !== this . _queryCount ) {
2080- return ;
2081- }
2082-
2113+ AbstractLovBase . prototype . _handleQueryResultsFetch = function ( ) {
20832114 // ignore a response if the oj-combobox has been closed before it was received
20842115 if ( ! this . isDropdownOpen ( ) ) {
20852116 return ;
@@ -2160,7 +2191,7 @@ AbstractLovBase.prototype._fetchFromDataProvider = function (term) {
21602191 filterCriteria = oj . FilterFactory . getFilter ( { filterDef : { text : term } } ) ;
21612192 }
21622193
2163- var retPromise = new Promise ( function ( resolve ) {
2194+ var retPromise = new Promise ( function ( resolve , reject ) {
21642195 // fetch data from dataProvider
21652196 var renderPromise = this . _lovDropdown . renderResults ( term , filterCriteria ,
21662197 LovUtils . isValueForPlaceholder ( this . _value ) ? null : this . _value ) ;
@@ -2171,17 +2202,25 @@ AbstractLovBase.prototype._fetchFromDataProvider = function (term) {
21712202 }
21722203
21732204 // 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+ }
21772211 } . bind ( this ) ;
21782212 renderPromise . then ( function ( ) {
21792213 afterRenderPromiseFunc ( ) ;
21802214 } , 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+ }
21822219 afterRenderPromiseFunc ( ) ;
21832220 } ) ;
21842221 } . bind ( this ) ) ;
2222+ // save the most recent promise so we can ignore old data provider responses
2223+ this . _lastDataProviderPromise = retPromise ;
21852224 return retPromise ;
21862225} ;
21872226
@@ -3987,6 +4026,22 @@ oj.__registerWidget('oj.ojSelect2', $.oj.editableValue, {
39874026 return returnValue ;
39884027 } ,
39894028
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+
39904045 /**
39914046 * @override
39924047 * @protected
0 commit comments