Skip to content

Unable to click the arrow icon to close combobox when dropdown appears #1693

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

Closed
adamint opened this issue Mar 14, 2024 · 14 comments
Closed

Unable to click the arrow icon to close combobox when dropdown appears #1693

adamint opened this issue Mar 14, 2024 · 14 comments
Labels
closed:done Work is finished

Comments

@adamint
Copy link
Member

adamint commented Mar 14, 2024

🐛 Bug Report

💻 Repro or Code Sample

This is present in the combobox examples: https://www.fluentui-blazor.net/Combobox (first discovered in the Aspire filter dialog).

🤔 Expected Behavior

Clicking the arrow button after the combobox is dropped down will close the dropdown.

😯 Current Behavior

Clicking the arrow does nothing. However, clicking outside the combobox will close it. Please see the videos here

🌍 Your Environment

Fluent UI Blazor 4.5, Chromium

@vnbaaij
Copy link
Collaborator

vnbaaij commented Mar 14, 2024

By coincidence an issue for this was opened for this just the other day in the fluent repo. There is also already a PR open to fix it in the FAST repo.
I'll ask what the schedule is to get it merged and then pullen into the web components script.

@adamint
Copy link
Member Author

adamint commented Mar 14, 2024

Oh that’s funny 😄 thanks, Vincent!

@vnbaaij vnbaaij added area:fast A FAST-specific issue area:fluent-ui-web-components A FluentUI specific issue labels Mar 15, 2024
@joriverm
Copy link
Contributor

joriverm commented Mar 15, 2024

ah ye, i noticed this too but saw it was in the webcomponents itself so i didn't report it here 😄

@vnbaaij vnbaaij added the status:blocked Any issue blocked by another label Mar 18, 2024
@chrisdholt
Copy link
Member

Coming soon - dependent PR for the stable release of Fluent: microsoft/fast#6942

@joriverm
Copy link
Contributor

@chrisdholt : its been nearly 2 months. are there any updates on the webcomponents update?

@hml-coder
Copy link
Contributor

hml-coder commented Jan 12, 2025

@vnbaaij @dvoituron Would you accept a PR similar to what's below for this issue since microsoft/fluentui/issues/30693 had a soft close in Sept. 2024?

The fluent-combobox template is using the onclick event so this PR (workaround) could register a click event on the dropdown indicator of that template and use a small delay to let the 'fluent-combobox' do it's thing before attempting to close the list.

FluentCombobox.razor.cs

 protected override async Task OnAfterRenderAsync(bool firstRender)
 {
     await base.OnAfterRenderAsync(firstRender);

     if (firstRender)
     {
         if (!string.IsNullOrEmpty(Id))
         {
             Module ??= await JSRuntime.InvokeAsync<IJSObjectReference>("import", JAVASCRIPT_FILE.FormatCollocatedUrl(LibraryConfiguration));
             await Module.InvokeVoidAsync("setControlAttribute", Id, "autocomplete", "off");
              
             await Module.InvokeVoidAsync("attachIndicatorClickHandler", Id);
             Debug.WriteLine($"combo: {Id}");
         }
     }
 }

FluentCombobox.razor.js

const handlers = new Map();

export function setControlAttribute(id, attrName, value) {
    const fieldElement = document.querySelector("#" + id)?.shadowRoot?.querySelector(".selected-value");

    if (!!fieldElement) {
        fieldElement?.setAttribute(attrName, value);
    }
}

export function attachIndicatorClickHandler(id) {
    const combobox = document.querySelector("#" + id);
    if (!combobox) return;

    const indicator = combobox.shadowRoot?.querySelector('[part="indicator"]');
    if (!indicator) return;

    // Use click with a 100ms delay
    indicator.addEventListener('click', (event) => {
        if (combobox.hasAttribute('open')) {
            setTimeout(() => {
                combobox.removeAttribute('open');
                console.log("Combo closed after delay");
            }, 100);
        }
    });

    // Store the handler for cleanup
    handlers.set(id, { combobox, indicator });
}

export function detachIndicatorClickHandler(id) {
    const handler = handlers.get(id);
    if (handler) {
        const { indicator } = handler;
        indicator.removeEventListener('click', handler.mouseup);
        handlers.delete(id);
        console.log(`Handler detached for combobox with id ${id}`);
    }
}

@dvoituron
Copy link
Collaborator

This could be a solution, but I don't like the fact that you have to remove the open attribute and use a timer?
Deleting a component element is always a risk with regard to its internal operation.
Using a timer to activate or engage an event can cause problems on other environments (WASM, browsers, MAUI).

In my opinion, this could be used, but only by adding an AllowClickOnClose attribute (or something like that).

@hml-coder
Copy link
Contributor

Ahhh...we need to be careful about altering the DOM. I posted a possible fix in the fluentui project microsoft/fluentui#30693 if you want to have a look. In the meantime I'll handle the workaround in my local projects.

@vnbaaij
Copy link
Collaborator

vnbaaij commented Jan 12, 2025

I don't think there will be a new version of the web components v2 anytime soon.

As @dvoituron said, we can do it on our side but we just need to make it 'opt-in'

@hml-coder
Copy link
Contributor

Thanks. I'm just now getting familiar the versioning of web technologies and how this all works. I'll do a PR if you think others would want this option.

AllowClickOnClose
AllowCloseWithClick

Any other suggestions?

@vnbaaij
Copy link
Collaborator

vnbaaij commented Jan 13, 2025

EnableClickToClose?

@hml-coder
Copy link
Contributor

Looking to get your thoughts on this approach.

Updated the JavaScript to dispatch an Escape key KeyboardEvent directly to the fluent-combobox, without using timers or altering the DOM structure.

const handlers = new Map();

export function attachIndicatorClickHandler(id) {
    const combobox = document.querySelector("#" + id);
    if (!combobox) return;

    const indicator = combobox.shadowRoot?.querySelector('[part="indicator"]');
    if (!indicator) return;

    // Click handler to simulate ESCAPE key press if combobox is open
    const clickHandler = (event) => {
        if (combobox.hasAttribute('open')) {
            event.preventDefault();
            event.stopImmediatePropagation();

            const escEvent = new KeyboardEvent('keydown', {
                key: 'Escape',
                code: 'Escape',
                keyCode: 27,
                bubbles: true,
                cancelable: true
            });

            combobox.dispatchEvent(escEvent);
        }
    };

    indicator.addEventListener('click', clickHandler);
    handlers.set(id, { indicator, clickHandler });
}

export function detachIndicatorClickHandler(id) {
    const handler = handlers.get(id);
    if (handler) {
        const { indicator, clickHandler } = handler;
        indicator.removeEventListener('click', clickHandler);
        handlers.delete(id);
    }
}

@dvoituron
Copy link
Collaborator

That sounds better to me

@hml-coder
Copy link
Contributor

Fixed in FluentCombobox with #3186

@vnbaaij vnbaaij added closed:done Work is finished and removed area:fast A FAST-specific issue area:fluent-ui-web-components A FluentUI specific issue status:blocked Any issue blocked by another labels Jan 17, 2025
@vnbaaij vnbaaij closed this as completed Jan 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed:done Work is finished
Projects
None yet
Development

No branches or pull requests

6 participants