Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

onChoicesLazyLoad isn't raised every time the search string changes if it happens rapidly #8419

Closed
jiyuan12354 opened this issue Jun 17, 2024 · 3 comments · Fixed by #8498
Closed
Assignees
Labels
dropdownV2 user issue An issue or bug reported by users
Milestone

Comments

@jiyuan12354
Copy link

jiyuan12354 commented Jun 17, 2024

Description:

I am experiencing an issue with the onChoicesLazyLoad event in SurveyJS Dropdown. While the event handler is generally functioning as expected, I have noticed a problem when users rapidly and frequently update the search filter. In such cases, the onChoicesLazyLoad event does not always fire consistently, leading to search results that do not reflect the user's most recent input.

Code Example:

survey.onChoicesLazyLoad.add((_, options) => {
  const choicesLazyLoadByUrl = options.question?.choicesLazyLoadByUrl;
  if (choicesLazyLoadByUrl?.url) {
    const url = `${choicesLazyLoadByUrl?.url}?skip=${options.skip}&take=${options.take}&filter=${options.filter}`;
    http.get(url, {}).then(({ data }) => {
      let _options;
      if (choicesLazyLoadByUrl?.path) {
        _options = get(data, choicesLazyLoadByUrl?.path);
      } else {
        _options = data;
      }
      const opts = _options.map((option) => {
        return {
          value: get(option, choicesLazyLoadByUrl.valueName, option.value),
          text: get(option, choicesLazyLoadByUrl.titleName, option.text),
        };
      });
      options.setItems(opts, data.total);
    });
  }
});

Issue Details:

  1. The choicesLazyLoadByUrl is a custom field and functions correctly.
  2. When users rapidly type into the search filter, the onChoicesLazyLoad event is sometimes skipped.
    This leads to the displayed choices not matching the user's latest input.

Expected Behavior:

The onChoicesLazyLoad event should fire for every change in the search filter, ensuring that the dropdown choices are always based on the latest input string.

Actual Behavior:

When the search filter is updated rapidly, some onChoicesLazyLoad events are not triggered, resulting in outdated search results.

image

Could you please investigate this issue and provide a solution to ensure that the onChoicesLazyLoad event fires correctly even with rapid input changes?

Thank you for your assistance.

@JaneSjs JaneSjs self-assigned this Jun 24, 2024
@JaneSjs JaneSjs added user issue An issue or bug reported by users dropdownV2 labels Jun 24, 2024
@JaneSjs JaneSjs assigned OlgaLarina and unassigned JaneSjs Jun 25, 2024
OlgaLarina pushed a commit that referenced this issue Jul 2, 2024
@OlgaLarina OlgaLarina linked a pull request Jul 2, 2024 that will close this issue
tsv2013 pushed a commit that referenced this issue Jul 4, 2024
…Changing Search Filter (#8498)

Co-authored-by: OlgaLarina <olga.larina.dev@gmail.com>
@jiyuan12354
Copy link
Author

@OlgaLarina Hi OlgaLarina, I reviewed your code changes, and I believe it's not advisable to remove isRunningLoadQuestionChoices directly, as it cannot guarantee that the later request will receive the response last. Suppose you send out Requests A and B sequentially, but there's a possibility that you might receive Responses B and A in that order, which could lead to new issues.
Actually I made a patch in my local.

DropdownListModel.prototype.updateQuestionChoices = function (callbackAfterItemsLoaded) {
        var _this = this;
        if (this.isRunningLoadQuestionChoices)
            return;
        var theLoadingFilterString = this.filterString;
        var isUpdate = (this.itemsSettings.skip + 1) < this.itemsSettings.totalCount;
        if (!this.itemsSettings.skip || isUpdate) {
            this.isRunningLoadQuestionChoices = true;
            this.question.survey.loadQuestionChoices({
                question: this.question,
                filter: this.filterString,
                skip: this.itemsSettings.skip,
                take: this.itemsSettings.take,
                setItems: function (items, totalCount) {
                    _this.isRunningLoadQuestionChoices = false;
                    _this.setItems(items || [], totalCount || 0);
                    _this.popupRecalculatePosition(_this.itemsSettings.skip === _this.itemsSettings.take);
                    if (!!callbackAfterItemsLoaded) {
                        callbackAfterItemsLoaded();
                    }
                    if (theLoadingFilterString !== _this.filterString) {
                        _this.itemsSettings.skip = 0;
                        _this.itemsSettings.items = [];
                        _this.updateQuestionChoices(callbackAfterItemsLoaded);
                    }
                }
            });
            this.itemsSettings.skip += this.itemsSettings.take;
        }
    };

@OlgaLarina OlgaLarina added this to the v1.11.6 milestone Jul 8, 2024
@RomanTsukanov RomanTsukanov changed the title Inconsistent onChoicesLazyLoad Triggering When Rapidly Changing Search Filter onChoicesLazyLoad isn't raised every time the search string changes if it happens rapidly Jul 9, 2024
@jiyuan12354
Copy link
Author

@OlgaLarina Hi OlgaLarina, I reviewed your code changes, and I believe it's not advisable to remove isRunningLoadQuestionChoices directly, as it cannot guarantee that the later request will receive the response last. Suppose you send out Requests A and B sequentially, but there's a possibility that you might receive Responses B and A in that order, which could lead to new issues. Actually I made a patch in my local.

DropdownListModel.prototype.updateQuestionChoices = function (callbackAfterItemsLoaded) {
        var _this = this;
        if (this.isRunningLoadQuestionChoices)
            return;
        var theLoadingFilterString = this.filterString;
        var isUpdate = (this.itemsSettings.skip + 1) < this.itemsSettings.totalCount;
        if (!this.itemsSettings.skip || isUpdate) {
            this.isRunningLoadQuestionChoices = true;
            this.question.survey.loadQuestionChoices({
                question: this.question,
                filter: this.filterString,
                skip: this.itemsSettings.skip,
                take: this.itemsSettings.take,
                setItems: function (items, totalCount) {
                    _this.isRunningLoadQuestionChoices = false;
                    _this.setItems(items || [], totalCount || 0);
                    _this.popupRecalculatePosition(_this.itemsSettings.skip === _this.itemsSettings.take);
                    if (!!callbackAfterItemsLoaded) {
                        callbackAfterItemsLoaded();
                    }
                    if (theLoadingFilterString !== _this.filterString) {
                        _this.itemsSettings.skip = 0;
                        _this.itemsSettings.items = [];
                        _this.updateQuestionChoices(callbackAfterItemsLoaded);
                    }
                }
            });
            this.itemsSettings.skip += this.itemsSettings.take;
        }
    };

No response here? I am sure there will have another issue by removing the isRunningLoadQuestionChoices flag.. your should fix it instead of removing it @OlgaLarina @RomanTsukanov @JaneSjs

@OlgaLarina
Copy link
Collaborator

Hello, @jiyuan12354
SurveyJS v1.11.4 introduces a dropdownSearchDelay setting that specifies how many milliseconds to wait before sending a search request to the server. You can find out more details here.
Therefore, isRunningLoadQuestionChoices is no longer needed.

Olga,
SurveyJS Team

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dropdownV2 user issue An issue or bug reported by users
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants