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

Dropdown: e.value undefined for keyDown event when optionValue prop is provided #7416

Open
abudd1094 opened this issue Nov 14, 2024 · 8 comments
Labels
Resolution: Workaround Issue or pull request contains a workaround. It needs to be reviewed further by Core Team Type: Bug Issue contains a defect related to a specific component.

Comments

@abudd1094
Copy link

abudd1094 commented Nov 14, 2024

Describe the bug

Prime React Version: 10.8.3

I have seen a previous issue with the same topic that has been resolved, however I still experience the following behavior:
#6316

This is using the source code from the first example "Basic" in the Prime React docs:
https://primereact.org/dropdown/#basic
image

If I select an option from the Dropdown without providing an "optionValue" prop, I am able to set an object value for selectedCity with both an onClick event and an onKeyDown event.
image

If I select an option from the Dropdown after providing an "optionValue" prop of "code" (to use the value of the "code" key as our "selectedCity" value), I am able to set a string value for selectedCity with an onClick event. I am unable to set a string value for selectedCity with an onKeyDown event because the value is undefined and not included anywhere in the event object.
image

As this behavior is happening in the "Basic" example with no additional alterations, I believe it is a bug with optionValue:
https://primereact.org/dropdown/#api.Dropdown.props.optionValue

Reproducer

https://stackblitz.com/edit/vitejs-vite-8dnhbw?file=src%2FApp.tsx

System Information

System:
    OS: macOS 13.6.9
    CPU: (10) arm64 Apple M1 Max
    Memory: 231.50 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.18.0 - ~/.nvm/versions/node/v20.18.0/bin/node
    npm: 10.8.2 - ~/.nvm/versions/node/v20.18.0/bin/npm
    pnpm: 8.7.6 - /usr/local/bin/pnpm
  Browsers:
    Brave Browser: 122.1.63.169
    Chrome: 131.0.6778.69
    Edge: 130.0.2849.80
    Safari: 16.6

Steps to reproduce the behavior

  1. Go to the stackblitz link above
  2. Open src/App.tsx
  3. Click near the dropdown on the left side to position cursor
  4. Press "tab" key to "focus" on the input (no focus styles in example, so don't expect visual feedback)
  5. Press "enter" key to open Dropdown and use arrow keys to make selection
  6. Press "enter" key again and observe no value has been set (e.value is undefined)
  7. Try to make a selection using the cursor and notice a value has been set

Expected behavior

The value should be set onKeyDown the same way it is set onClick when the optionValue prop is defined.

@abudd1094 abudd1094 added the Status: Needs Triage Issue will be reviewed by Core Team and a relevant label will be added as soon as possible label Nov 14, 2024
@melloware
Copy link
Member

you didn't mention your PrimeReact version?

@abudd1094
Copy link
Author

you didn't mention your PrimeReact version?

Thanks for catching, added at top of description

@melloware
Copy link
Member

can you try 10.8.4?

@abudd1094
Copy link
Author

can you try 10.8.4?

Unfortunately, the issue is still present after updating to 10.8.4

@melloware
Copy link
Member

OK excellent thanks for checking.

@melloware melloware added Type: Bug Issue contains a defect related to a specific component. and removed Status: Needs Triage Issue will be reviewed by Core Team and a relevant label will be added as soon as possible labels Nov 14, 2024
@abudd1094
Copy link
Author

abudd1094 commented Nov 14, 2024

For anyone in need of a temporary solution, you can try handling onKeyDown explicitly in the "onChange" prop:

/**
   * Handles the key down event for the input dropdown.
   *
   * @param {React.KeyboardEvent} e - The keyboard event object.
   * @returns {void}
   *
   * This function checks if the pressed key is 'Enter' or 'Space'.
   * If so, it finds the selected option from the options array based on the text content of the original event target.
   * If a matching option is found, it sets the selected value using the optionValue property.
   *
   * @remarks This is a workaround for the issue linked above where the dropdown has an e.value of undefined when the user selects an option using the keyboard.
   */
  const handleKeyDown = (e: DropdownChangeEvent) => {
    if (
      !!onChange &&
      !!options &&
      !!optionValue &&
      !!optionLabel &&
      // check if key is 'Enter' or 'Space'
      ((e.originalEvent as unknown as KeyboardEvent)?.code === 'Enter' ||
        (e.originalEvent as unknown as KeyboardEvent)?.code === ' ')
    ) {
      // use new variable for options in case we need to mutate in the following block
      let flattenedOptions = options;

      // if using option groups we need to go a level deeper to access the options
      if (optionGroupChildren) {
        flattenedOptions = options.flatMap(
          (optionGroup) => optionGroup[optionGroupChildren],
        );
      }

      // find the selected option manually based on the text content of the event target
      const selectedOption = flattenedOptions.find(
        (option) =>
          option[optionLabel] ===
          (e.originalEvent?.target as HTMLElement).textContent,
      );

      // if a matching option is found, add the value to the event object to match behavior of onClick event
      if (selectedOption) {
        e.value = selectedOption[optionValue];
        onChange(e);
      }
    }
  };

  /**
   * Handles the change event for the dropdown component when `optionValue` prop is present.
   * We wrap the keydown handler in the onChange instead of a separate onKeydown function to
   * avoid setting undefined values in state during the onChange event.
   *
   * @param {DropdownChangeEvent} e - The change event object from the dropdown.
   *
   * If the `optionValue` prop is defined, it checks the type of the original event.
   * If the original event type is 'keydown', it calls the `handleKeyDown` function.
   * Otherwise, it calls the `onChange` function.
   */
  const handleChange = (e: DropdownChangeEvent) => {
    if (onChange) {
      if (!!optionValue && e.originalEvent?.type === 'keydown') {
        handleKeyDown(e);
      } else {
        onChange(e);
      }
    }
  };

@melloware melloware added the Resolution: Workaround Issue or pull request contains a workaround. It needs to be reviewed further by Core Team label Nov 14, 2024
@abudd1094
Copy link
Author

abudd1094 commented Nov 14, 2024

Very quick @melloware , I was trying to format that cleanly. Thanks for your help, quick response, and good work. We love the library!

@melloware
Copy link
Member

no problem in the future use 3 ticks with js like this "```js"
and 3 ticks to close it!

Also I don't work for PrimeTek i am just an open source contributor like you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Workaround Issue or pull request contains a workaround. It needs to be reviewed further by Core Team Type: Bug Issue contains a defect related to a specific component.
Projects
None yet
Development

No branches or pull requests

2 participants