Skip to content

fix(components): [select] correctly display selected labels after options change#24036

Merged
btea merged 7 commits into
element-plus:devfrom
LostElkByte:fix/select-remote-search-label
Apr 25, 2026
Merged

fix(components): [select] correctly display selected labels after options change#24036
btea merged 7 commits into
element-plus:devfrom
LostElkByte:fix/select-remote-search-label

Conversation

@LostElkByte
Copy link
Copy Markdown
Contributor

@LostElkByte LostElkByte commented Apr 13, 2026

Fixes selected items showing raw value instead of label when remote search
options change.

Root cause

The template renders options with :key="index", so Vue reuses option
components instead of destroying/recreating them. When props update:

  1. onOptionDestroy(oldVal) + onOptionCreate(vm) fire from the value watcher
  2. cachedOptions retains stale keys pointing to VMs whose value has changed
  3. getOption() iterates by vm.value — no match → falls back to raw value

Fix

In getOption, before the raw-value fallback, check states.selected for
a previously resolved label.

issue

fix #23624

Summary by CodeRabbit

  • Bug Fixes

    • Selected labels in multi-select dropdowns now remain stable when remote option results refresh; previously chosen items keep their displayed label and underlying value after subsequent remote queries and list updates.
  • Tests

    • Added automated test coverage to validate selection label and value persistence across successive remote updates and option list refreshes.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 13, 2026

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

getOption in the select hook now reuses an existing selected entry’s currentLabel when no cached option is found; a Vitest was added to verify a selected option’s label persists across remote-search result updates.

Changes

Cohort / File(s) Summary
Test Case Addition
packages/components/select/__tests__/select.test.ts
Added a Vitest that mounts a multiple, filterable, remote el-select, drives two remote queries ("foo""bar") using fake timers, selects an option after the first query, and asserts the selected item's currentLabel and value remain unchanged after the second query.
Select logic change
packages/components/select/src/useSelect.ts
In getOption, when no cached option matches the value, first look up states.selected for an existing selected entry and reuse its currentLabel (for primitive and object values) before falling back to the raw value; preserves prior object-value label precedence.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • rzzf
  • btea
  • keeplearning66

Poem

🐰 I nibble labels soft and bright,
Hopping through queries left and right.
When options wander, stray, or roam,
My chosen tag still calls it home.
🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The description explains the root cause, the fix applied, and references the linked issue, though it lacks explicit checkboxes from the template.
Linked Issues check ✅ Passed The code changes directly address issue #23624 by implementing the fix to preserve selected item labels during remote search option updates.
Out of Scope Changes check ✅ Passed All changes are focused on fixing the remote search label issue: a test case validates the fix and useSelect.ts implements the label lookup logic.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title correctly identifies the main fix: ensuring selected labels display correctly after options change in el-select, which directly addresses the changeset's core objective of preserving labels during remote search updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 13, 2026

Open in StackBlitz

pnpm add https://pkg.pr.new/element-plus@24036
npm i https://pkg.pr.new/element-plus@24036
yarn add https://pkg.pr.new/[email protected]

commit: ee3f5ae

@github-actions github-actions Bot added the CommitMessage::Unqualified Unqualified commit message label Apr 13, 2026
@LostElkByte LostElkByte changed the title fix(components): [select] preserve selected label on remote options change (#23624) fix(components): [select] preserve selected label on remote search (#23624) Apr 13, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/components/select/__tests__/select.test.ts (1)

4579-4631: Make timer cleanup exception-safe.

If anything throws before Line 4630, fake timers remain active and may destabilize later tests. Wrap test body in try/finally and restore timers there.

Proposed test-hardening diff
   test('should preserve selected label when remote options change', async () => {
     vi.useFakeTimers()
     const wrapper = mount(
@@
       },
       { attachTo: 'body' }
     )
-
-    const select = wrapper.findComponent({ name: 'ElSelect' }).vm
-    select.onInput({ target: { value: 'foo' } })
-    vi.runAllTimers()
-    await nextTick()
-    getOptions()[0].click()
-    await nextTick()
-    expect(select.states.selected[0].currentLabel).toBe('Label foo-0')
-
-    select.onInput({ target: { value: 'bar' } })
-    vi.runAllTimers()
-    await nextTick()
-
-    expect(select.states.selected[0].currentLabel).toBe('Label foo-0')
-    vi.useRealTimers()
+    try {
+      const select = wrapper.findComponent({ name: 'ElSelect' }).vm
+      select.onInput({ target: { value: 'foo' } })
+      vi.runAllTimers()
+      await nextTick()
+      getOptions()[0].click()
+      await nextTick()
+      expect(select.states.selected[0].currentLabel).toBe('Label foo-0')
+
+      select.onInput({ target: { value: 'bar' } })
+      vi.runAllTimers()
+      await nextTick()
+
+      expect(select.states.selected[0].currentLabel).toBe('Label foo-0')
+    } finally {
+      wrapper.unmount()
+      vi.useRealTimers()
+    }
   })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/components/select/__tests__/select.test.ts` around lines 4579 -
4631, The test enables fake timers with vi.useFakeTimers() but only restores
them at the end, so if something throws the fake timers remain active; wrap the
test body (after vi.useFakeTimers()) in a try { ... } finally {
vi.useRealTimers() } block so that vi.useRealTimers() is always called (ensure
the existing interactions with wrapper, select.vm, select.onInput,
vi.runAllTimers(), nextTick, getOptions(), etc. remain inside the try).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/components/select/__tests__/select.test.ts`:
- Around line 4579-4631: The test enables fake timers with vi.useFakeTimers()
but only restores them at the end, so if something throws the fake timers remain
active; wrap the test body (after vi.useFakeTimers()) in a try { ... } finally {
vi.useRealTimers() } block so that vi.useRealTimers() is always called (ensure
the existing interactions with wrapper, select.vm, select.onInput,
vi.runAllTimers(), nextTick, getOptions(), etc. remain inside the try).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dc5f75c1-7e64-4920-945d-12aa105be33a

📥 Commits

Reviewing files that changed from the base of the PR and between 9f4f884 and c094f37.

📒 Files selected for processing (2)
  • packages/components/select/__tests__/select.test.ts
  • packages/components/select/src/useSelect.ts

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c094f37b38

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/components/select/src/useSelect.ts Outdated
@LostElkByte LostElkByte changed the title fix(components): [select] preserve selected label on remote search (#23624) fix(components): [select] selected label on remote search (#23624) Apr 13, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 13, 2026

🧪 Playground Preview: https://element-plus.run/?pr=24036
Please comment the example via this playground if needed.

@github-actions github-actions Bot removed the CommitMessage::Unqualified Unqualified commit message label Apr 13, 2026
@LostElkByte LostElkByte changed the title fix(components): [select] selected label on remote search (#23624) fix(components): [select] selected label on remote search Apr 13, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d14dc2b555

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/components/select/src/useSelect.ts Outdated
@LostElkByte
Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link
Copy Markdown
Member

@keeplearning66 keeplearning66 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newly added test case seems to pass even before the changes. 🤔