Skip to content

Latest commit

 

History

History
269 lines (234 loc) · 9.74 KB

inputs-open-programmatically.md

File metadata and controls

269 lines (234 loc) · 9.74 KB
title description type page_title slug position tags ticketid res_type
Open Input Dropdown on Focus
How to open the component dropdown (popup) programmatically or when the user focuses the textbox.
how-to
Open Input Dropdown Programmatically on Focus
inputs-kb-open-programmatically
autocomplete,combobox,datepicker,datetimepicker,dropdown,dropdownlist,multicolumncombobox,multiselect,timepicker,focus,open
1526273, 1539587, 1547004, 1562064, 1475760
kb

Environment

Product AutoComplete for Blazor,
ComboBox for Blazor,
DatePicker for Blazor,
DateTimePicker for Blazor,
DropDownList for Blazor,
MultiColumnComboBox for Blazor,
MultiSelect for Blazor,
TimePicker for Blazor
Product Version 3.5.0 and later

Description

This Knowledge Base article covers multiple scenarios:

  • How to show the AutoComplete dropdown automatically when the user clicks inside the input?
  • How to open the ComboBox dropdown on component focus via click?
  • How to expand the item list when the ComboBox input is focused via tab?
  • How to open the MultiSelect popup from code?
  • How to open the MultiSelect list during keyboard navigation tabbing?
  • How to show the Calendar or Time popup immediately when the user focuses the Date/Time Picker textbox?

Solution

To begin with, all Telerik inputs and dropdowns have an Open method.

The DropDownList and MultiSelect open automatically on click. They need JavaScript code only to open on focus.

The AutoComplete, ComboBox and Date/Time Pickers do not open automatically and need JavaScript for all use cases - focus and click.

Review the attachFocusHandler JavaScript function below. It is called in OnAfterRenderAsync and attaches a focus handler to each component textbox. The handler simulates an Alt + Down keyboard shortcut, which opens the dropdowns as a standard accessibility and usability feature.

Note that the Date/Time Pickers move focus to their popup once it is opened. This enables keyboard navigation in the popup, but prevents immediate move to another component via tabbing. You need to hit Enter to close the popup and return focus to the DateInput textbox. Then tab.

Replace the OnFocusKB type of the DotNetObjectReference in the example below with the type of the component that hosts this code.

caption Focus Component and Open Dropdown Programmatically

````RAZOR @inject IJSRuntime js @* Open dropdown on click or focus *@ <script suppress-error="BL9992"> var dotNet; function saveDotNetRef(dotNetRef) { dotNet = dotNetRef; } function attachFocusHandler(id) { var element = document.getElementById(id); if (element) { element.addEventListener("focus", (event) => { dotNet.invokeMethodAsync("OpenComponent", id); }); } } </script>

AutoComplete:

ComboBox:

MultiColumnComboBox:

DropDownList:

MultiSelect:

DatePicker:

TimePicker:

@code { //Replace the OnFocusKB type with the type of the component that hosts this code private DotNetObjectReference? DotNetRef { get; set; }

private List<Product> ValueCollection { get; set; } = new();
private List<int> MultiValues { get; set; } = new();
private int IntValue { get; set; }
private string StringValue { get; set; }
private DateTime DateValue { get; set; } = DateTime.Now;

private Dictionary<string, Action> ComponentRefs { get; set; } = new();

private TelerikMultiSelect<Product, int>? MultiSelectRef { get; set; }
private TelerikAutoComplete<Product>? AutoCompleteRef { get; set; }
private TelerikComboBox<Product, int>? ComboBoxRef { get; set; }
private TelerikMultiColumnComboBox<Product, int>? MultiComboBoxRef { get; set; }
private TelerikDropDownList<Product, int>? DropDownListRef { get; set; }
private TelerikDatePicker<DateTime>? DatePickerRef { get; set; }
private TelerikTimePicker<DateTime>? TimePickerRef { get; set; }

[JSInvokable("OpenComponent")]
public void OpenComponent(string id)
{
    Action action = ComponentRefs[id];

    action.Invoke();
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await Task.Delay(1); // ensure HTML is ready
        await js.InvokeVoidAsync("saveDotNetRef", DotNetRef);

        await js.InvokeVoidAsync("attachFocusHandler", AutoCompleteRef.Id);
        await js.InvokeVoidAsync("attachFocusHandler", ComboBoxRef.Id);
        await js.InvokeVoidAsync("attachFocusHandler", MultiComboBoxRef.Id);
        await js.InvokeVoidAsync("attachFocusHandler", DatePickerRef.Id);
        await js.InvokeVoidAsync("attachFocusHandler", TimePickerRef.Id);
        await js.InvokeVoidAsync("attachFocusHandler", DropDownListRef.Id);
        await js.InvokeVoidAsync("attachFocusHandler", MultiSelectRef.Id);
    }

    await base.OnAfterRenderAsync(firstRender);
}

protected override void OnInitialized()
{
    ComponentRefs = new Dictionary<string, Action>()
    {
        { "AC1", () => AutoCompleteRef.Open() },
        { "CB1", () => ComboBoxRef.Open() },
        { "MCCB1", () => MultiComboBoxRef.Open() },
        { "DDL1", () => DropDownListRef.Open() },
        { "MS1", () => MultiSelectRef.Open() },
        { "DP1", () => DatePickerRef.Open() },
        { "TP1", () => TimePickerRef.Open() },
    };

    for (int i = 1; i <= 10; i++)
    {
        ValueCollection.Add(new Product()
            {
                ID = i,
                Name = "Product Name " + i.ToString()
            });
    }

    DotNetRef = DotNetObjectReference.Create(this);

    base.OnInitialized();
}

public class Product
{
    public int ID { get; set; }
    public string Name { get; set; }
}

}


## Versions Before 3.0

[UI for Blazor versions 2.25 - 2.30 have different HTML rendering for the input components](slug:changes-in-3-0-0). Use this `attachFocusHandler` code instead:

<div class="skip-repl"></div>
````JS
function attachFocusHandler(id, componentClass) {
    var element = document.getElementById(id);
    if (element) {
        element.addEventListener("focus", (event) => {
            var keyEvent = new KeyboardEvent("keydown", {
                "altKey": true,
                "code": "ArrowDown",
                "key": "ArrowDown",
                "keyCode": 40
            });
            if ((componentClass == ".k-multiselect" && (!event.relatedTarget || event.relatedTarget != element.parentNode.parentNode))
                || (componentClass != undefined && componentClass != ".k-multiselect")) {
                // AutoComplete, ComboBox, DatePicker, TimePicker - tab, click, FocusAsync
                // MultiSelect - tab, FocusAsync
                // element is an input, so we go up the DOM tree to find the component root
                element.closest(componentClass).dispatchEvent(keyEvent);
            } else {
                // DropDownList - tab, FocusAsync
                // element is a span and this is the component root
                element.dispatchEvent(keyEvent);
            }
        });
    }
}