Why does wiping the search field do a search with minimumInputLength?


#1

Repro:

  1. With an Ajax data source and placeholder text
  2. Do a search and wait for results to populate
  3. Clear the search box

Expected:
The placeholder text is shown

Actual:
An Ajax search is done for the minimumInputLength number of characters from the search done in step 2. Example, if minimumInputLength is 2, and you search for “matt”, and then clear the search results, you’ll see results for a search for “ma”.

Video:

JSBin:
I’m using the GitHub repo example from the Select2 docs

Related question:

  • If tags: true is set, why does the selected input box populate with the tag? You can see in this video (same JS Bin) that searching for an item that’s not in the list will populate the selected box. Seems like a bug?

#2

Hi, Kareem–

For issue #1, this seems like a timing issue. You’re backspacing over characters, and my guess is that each change in the input box (i.e., each deleted character) fires off an AJAX request unless you use the AJAX rate-limiting feature. Try setting the delay value to something in the range of 150–250, and see if that fixes the issue.

For issue #2, I’m not quite sure I understand what you’re describing. I don’t see that behavior when I use the AJAX example in the Select2 docs, but that’s probably because that example doesn’t have the tags feature enabled.

That said, the purpose of the tags feature is to allow selections that aren’t in the data set. I guess you’re questioning why the tag gets created if the user hasn’t pressed Enter. This might be a bug; my guess is that it has something to do with how the AJAX request gets fired after the user stops typing.

Maybe the rate-limiting option will solve this issue too; if not, you might try constraining tag creation, although what criteria you would use to determine whether the user “intentionally” created the tag is not clear. A possible approach would be to attach a keydown event handler to the Select2’s input field (input.select2-search__field) that sets a boolean variable (to true) when the user presses Enter in the field (indicating that they want to create a tag), and unsets the variable when the user presses any other key. Then your tag constraint function would check that variable and only allow the tag to be created if the variable is true. I’m not postitive this would work (there might be timing issues if the Select2 calls your tag constraint function before the keydown event fires, although that doesn’t seem logical), but even though it’s a hack, I think it’s worth a try. (it wouldn’t be the first time I’ve had to hack my way around some odd behavior or unsupported capability of the Select2. :smile:)


#3

Hey @John30013, thanks for the response.

For issue #1, this seems like a timing issue. You’re backspacing over characters, and my guess is that each change in the input box (i.e., each deleted character) fires off an AJAX request unless you use the AJAX rate-limiting feature. Try setting the delay value to something in the range of 150–250, and see if that fixes the issue.

That was my original thinking too. I’ve tried a delay of 100, 250, 500, 1000, and 2000ms, and get the same result. It’s easy to play with in the JSBin linked in the original post.

I guess you’re questioning why the tag gets created if the user hasn’t pressed Enter.

Exactly. I’m surprised I haven’t seen mention of this anywhere. But the JSBin example is pretty vanilla; I don’t think there’s anything special going on there. Appreciate the suggestion, I’ll bang on it and see what I come up with :slight_smile:


#4

Hi, Kareem,

This bug happens to me too on a production website where I’m using Select2 with an Ajax data source. However, I’m also using Select2 on another site with a remote data source, but in that case I’m retrieving the data myself (via the JavaScript fetch API), loading the retrieved data into a Select2 data object array, and initializing the widget with that array. In that case I don’t experience the bug. So depending on the size of your remote data set, that could be an option for you too.


#5

Thanks @John30013. Are you referring to bug #1 or bug #2? :slight_smile:


#6

Hi, @kareem~~

I was talking about bug #1. I was thinking about it some more last night, and I came up with a workaround for it in my own application, but it relies on specifying the transport function (which my code was already using). I added this code at the beginning of my transport function:

var curSearchText = $('input.select2-search__field').val();
if (curSearchText !== params.data.term) {
    return;
}
// Actual AJAX query logic goes here.

I had to adjust the delay parameter to 500 so it would work if the user just holds down the Backspace key (because there’s a delay before the keyboard’s auto-repeat kicks in), but this works for my application.

If you’re not using a custom transport function, I think you could accomplish a similar effect with a custom ajax.processResults function: in that function you would check whether the current value in the input field (i.e., $('input.select2-search__field').val().length) is less than the minimum input length. If it is, you return an empty array; otherwise you do whatever processing you’d normally do (or the minimal processing required) to return the results. You’ll still take the hit for the “unwanted” AJAX call, but at least the user won’t see the results from it. (I’ve confirmed this works in the JSBin.)

This solution still has the #2 bug (I can see the “unwanted” tag being created), but similar logic in the createTag function fixes that (also confirmed in the JSBin):

createTag: function (params) {
  var term = $.trim(params.term);
  if (term === '' || $('input.select2-search__field').val().length < 2) {
    return null;
  }
  return {
    id: term,
    text: term,
    newTag: true
  }
},

Let me know if you make progress with this issue.

~~John