primefaces / primereact

The Most Complete React UI Component Library
https://primereact.org
MIT License
6.9k stars 1.05k forks source link

Dropdown: rendering problem when used in a Dialog #2683

Closed SunshineyDay closed 1 year ago

SunshineyDay commented 2 years ago

Codesandbox Case (Bug Reports) https://codesandbox.io/s/primereact-dialog-dropdown-issue-teiqoz

Current behavior The PrimeReact Dropdown component, when used in a PrimeReact Dialog, suffers from a rendering problem where the dropped-down list becomes detached from the input when the dialog's parent is scrolled.

Expected behavior Dropdown should not be affected by scrolling the parent component.

Minimal reproduction of the problem with instructions Create a component that uses a Dialog component. In the Dialog include a Dropdown that has filtering turned on. Make sure the Dialog's parent has enough content to show scrollbars. Open the dialog, drop down the list, scroll the parent - observe that the dropped-down list moves with the parent rather than staying in place with the list input.

Please tell us about your environment: Issue occurs both locally on Windows 10 dev PC and in Codesandbox.

image

melloware commented 2 years ago

In other Prime libraries we close the drop down panel when scrolling.

ghost commented 2 years ago

Hello. I cannot figure out how to fix this bug with Dropdown. Below is my implementation of the component. Can anyone support how to fix it ? <StyledDropdown name={luxmeds.${index}.luxmedType.package} value={luxmedType.package} options={luxmedPackages} onChange={handleChange} placeholder="Select a package" />

melloware commented 1 year ago

Workaround posted by user:

// This is a temporary workaround for a bug where the dropdown options move during scrolling.
// There is a proposed solution but the PR hasn't been approved.
// https://github.com/primefaces/primereact/issues/2683
// https://github.com/primefaces/primereact/pull/2757

import {useEffect} from "react";

export const useHideSelectOptionsOnScroll = () => {
    const containers = document.querySelectorAll('.p-sidebar-content, .p-dialog-content');

    useEffect(() => {
        const scrollEventHandler = () => {
            const dropdownOptions = document.querySelectorAll('.p-dropdown-panel,.p-multiselect-panel');
            // Hack: Casting activeElement as 'any' in order to use 'blur', which is otherwise not allowed
            // and requires jumping through myriad hoops
            const activeElement = document.activeElement as any;
            activeElement?.blur();
            // Only one set of options will be open at a time
            dropdownOptions[0] && dropdownOptions[0].classList.add('hidden');
        };

        // NOTE: setTimeout is used because for some reason, Prime components can't be found with document.querySelector
        // until some time elapses, even though they're immediately visible
        setTimeout(() => {
            window.addEventListener('scroll', scrollEventHandler);
            containers.forEach(x => x.addEventListener('scroll', scrollEventHandler));
        }, 500);
    }, [containers]);
};
melloware commented 1 year ago

In 9.5.0 you can now set PrimeReact.hideOverlaysOnDocumentScrolling = true; and achieve this functionality desired.