Repository navigation
fix: create ParticipantSelect's debounced loader before mount - #10
Conversation
v-autocomplete syncs its search model while it mounts, which runs the `search` watcher before the parent's onMounted hook. The debounced loader was only created in onMounted, so the watcher called null and the console showed "debouncedGetIndividualData is not a function" (minified: "l is not a function") every time a participant select opened. Create the debounced function in setup; onMounted keeps the initial load. Regression test mounts the component and asserts no error escapes and the individuals API is queried. Introduced upstream in Netflix#3925. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Approval recommended
The change is a minimal, correct relocation of the debounce creation that resolves the documented error and is covered by a regression test following established repo patterns.
No open issues 🎉
What changed in this PR
This PR fixes a runtime TypeError (debouncedGetIndividualData is not a function) that occurred whenever a ParticipantSelect was opened. The root cause is that Vuetify's v-autocomplete syncs its search model during mount—before the parent's onMounted hook—so the watch(search, …) callback invoked the debounced loader while it was still null. The fix creates the debounced loader in setup() so it exists before any watcher fires, keeping the component's search-as-you-type behavior intact.
Changes:
- Move
debouncedGetIndividualData = debounce(getIndividualData, 300)fromonMountedinto thesetup()body (now aconst), withonMountedretaining only the initial load. - Add a regression test that mounts the component with a mocked individuals API, captures Vue errors / unhandled rejections, and asserts none escape while the API is still queried after the debounce.
| File | Description |
|---|---|
src/dispatch/static/dispatch/src/components/ParticipantSelect.vue |
Creates the debounced loader in setup() before mount so the search watcher can safely call it. |
src/dispatch/static/dispatch/src/tests/participantSelectSearchBeforeMount.spec.js |
New test reproducing the pre-mount search error and verifying the fix. |
Review effort: Balanced
Bug
Opening any participant select (incident detail pane, handoff dialog, task owner, incident filter) logs
TypeError: l is not a functionfromParticipantSelect-*.js. Unminified:debouncedGetIndividualData is not a function.v-autocompletesyncs itssearchmodel while it mounts, i.e. before the parent'sonMountedhook, and thewatch(search, …)callback calls the debounced loader, which until now was created only inonMounted. Introduced upstream in Netflix#3925.Fix
Create
debouncedGetIndividualDatawithdebounce()insetup();onMountedkeeps the initial load. One-line move.Test
src/tests/participantSelectSearchBeforeMount.spec.jsmounts the component with a mocked individuals API, collects Vue errors and unhandled rejections, and asserts none escape and the API is queried after the debounce. Fails onmainwith exactly the production error, passes with the fix.🤖 Generated with Claude Code