This is a migrated thread and some comments may be shown as answers.

[Solved] Correcting the Tab Order for RadComboBox with embedded Controls in the DropDown List

0 Answers 192 Views
ComboBox
This is a migrated thread and some comments may be shown as answers.
instigator
Top achievements
Rank 1
instigator asked on 24 Apr 2009, 02:34 PM
I recently had to develop a multi-select dropdownlist with a checkbox control for each item. There must also be a value in each dropdown for "ALL" that checks all the controls when checked and unchecks them all when "ALL" is unchecked. When delivered to the client they noticed the tab order is WAY off when you do this. Here is the solution I came up with to get more of the natural tab order that a web page should have.

First set a template for the RadComboBoxItem Control in the code behind and set all the Client JavaScript methods.

//rcb is the RadComboBox

rcb.ItemTemplate = new CheckBoxTemplate();
rcb.OnClientDropDownOpening = "OnClientDropDownOpening";
rcb.OnClientDropDownClosing = "OnClientDropDownClosing";
rcb.OnClientSelectedIndexChanging = "OnClientSelectedIndexChanging";
rcb.OnClientBlur = "OnClientBlur";
rcb.OnClientLoad = "OnClientLoad";
rcb.OnClientFocus = "OnClientFocus";
rcb.OnClientKeyPressing = "OnClientKeyPressing";
rcb.MarkFirstMatch = true;
rcb.CloseDropDownOnBlur = true;


Here is the template Class

// =======================================================================================================
    class CheckBoxTemplate : CheckBox, ITemplate
    {
        public void InstantiateIn(Control container)
        {
            CheckBox checkBox = new CheckBox();
            checkBox.ID = "CheckBox";
          
            checkBox.DataBinding += new EventHandler(checkBox_DataBinding);
             
            RadComboBoxItem item = container as RadComboBoxItem;
            if (item != null)
            {
                if (!string.IsNullOrEmpty(item.Value))
                    container.Controls.Add(checkBox);
            }
        }
                 
        private void checkBox_DataBinding(object sender, EventArgs e)
        {
            CheckBox target = (CheckBox)sender;
               
            RadComboBoxItem item = (RadComboBoxItem)target.BindingContainer;
            string itemText = (string)DataBinder.Eval(item, "Text");
            target.Text = itemText;
            
            target.Attributes.Add("onKeyDown", "return OnClientKeyPressing(event, '" + target.Parent.Parent.ClientID + "');");
            bool itemSelected = (bool)DataBinder.Eval(item, "Selected");
            target.Checked = itemSelected;
            target.Attributes.Add("onclick", "checkboxClick('" + target.Parent.Parent.ClientID + "', '" + target.Text + "');");
        }
    }

// ==================================================================================================

Here is the javascript for the client events. Some of this was "borrowed" from another forum post and extended.


var supressDropDownClosing = false;

function OnClientKeyPressing(evt, sender) {

    if (sender != null) {
        var key = (evt.which) ? evt.which : event.keyCode;

        if (!event.shiftKey) {
        //Treat enter and tab the same so the form doesn't submit.
            if (key == 9 || key == 13) {

                
                var s;
                try {
                    s = $find(sender);
                }
                catch (err) {
                    s = sender;
                }



                try {
                    //get the input element of the RadComboBox and set the focus
                    s.get_inputDomElement().focus();


                    //Get the dropdown DOM element of the RadComboBox and set visibility to hidden;
                    s.get_dropDownElement().style.visibility = 'hidden';
                }
                catch (err) {
                    //exception gets thrown if you come in from a textbox.
                }

                //Pass back the tab keyCode so the app will tab to the next column
                event.keyCode = 9;

            }
        }

        //if the user hits the down arrow, do the default tab
        if (key == 40) {
            event.keyCode = 9;
        }
    }

    return event;
}

function OnClientFocus(sender) {
    
    var combo;
    try {
        combo = $find(sender);
    }
    catch (err) {
        combo = sender;
    }

    combo.toggleDropDown();
    try {
        var items = combo.get_items();

        var item = items.getItem(0);
        var checkbox = getItemCheckBox(item);
        checkbox.focus();
    }
    catch (err) {
    }
    
}

function OnClientDropDownClosing(sender, eventArgs) {
    eventArgs.set_cancel(supressDropDownClosing);
}

function OnClientSelectedIndexChanging(sender, eventArgs) {
    eventArgs.set_cancel(supressDropDownClosing);
}

function OnClientDropDownOpening(sender, eventArgs) {
    supressDropDownClosing = true;
}

function OnClientBlur(sender) {
    supressDropDownClosing = false;

    sender.toggleDropDown();
}

function checkboxClick(combo, checkClicked) {
    collectSelectedItems(combo, checkClicked);
}

function OnClientLoad(sender, eventArgs) {
    var items = sender.get_items();
    var itemIndex;
    var selectedItemsTexts = "";
    var selectedItemsValues = "";
    var isAllSelected = false;
    var itemsCount = items.get_count();


    for (itemIndex = 0; itemIndex < itemsCount; itemIndex++) {
        var item = items.getItem(itemIndex);
        var checkbox = getItemCheckBox(item);

        if (checkbox != null) {
            if (item.get_text() == "ALL" && checkbox.checked == true) {
                isAllSelected = true;
            }

            //Check whether the Item's CheckBox) is checked.
            if (checkbox.checked) {
                selectedItemsTexts += item.get_text() + ", ";
                selectedItemsValues += item.get_value() + ", ";
            }
        }
    }

    selectedItemsTexts = selectedItemsTexts.substring(0, selectedItemsTexts.length - 2);
    selectedItemsValues = selectedItemsValues.substring(0, selectedItemsValues.length - 2);

    if (isAllSelected) {
        selectedItemsTexts = "ALL";
    }
    //Set the text of the RadComboBox with the texts of the selected Items, separated by ','.

    if (selectedItemsTexts == "")
        selectedItemsTexts = "<Please Select>";


    sender.set_text(selectedItemsTexts);


}
function getItemCheckBox(item) {
    //Get the 'div' representing the current RadComboBox Item.
    var itemDiv = item.get_element();

    //Get the collection of all 'input' elements in the 'div' (which are contained in the Item).
    var inputs = itemDiv.getElementsByTagName("input");

    for (var inputIndex = 0; inputIndex < inputs.length; inputIndex++) {
        var input = inputs[inputIndex];

        //Check the type of the current 'input' element.
        if (input.type == "checkbox") {
            return input;
        }
    }

    return null;
}



function collectSelectedItems(combo2, checkClicked) {
    var combo;
    try {
        combo = $find(combo2);
    }
    catch (err) {
        combo = combo2;
    }

    var items = combo.get_items();
    var selectedItemsTexts = "";
    var selectedItemsValues = "";

    var itemsCount = items.get_count();
    var isAllSelected = false;
    var itemIndex;

    var numunchecked = 0;


    for (itemIndex = 0; itemIndex < itemsCount; itemIndex++) {
        var item = items.getItem(itemIndex);
        var checkbox = getItemCheckBox(item);

        if (checkbox != null) {
            if (item.get_text() == "ALL" && checkClicked == "ALL" && checkbox.checked == true) {
                isAllSelected = true;
            }
        }
    }


    for (itemIndex = 0; itemIndex < itemsCount; itemIndex++) {
        var item = items.getItem(itemIndex);
        var checkbox = getItemCheckBox(item);

        if (checkbox != null) {

            if (isAllSelected) {
                checkbox.checked = true;
            }

            if (!isAllSelected && item.get_text() == "ALL")
                checkbox.checked = false;

            if (checkClicked == "ALL" && !isAllSelected) {
                checkbox.checked = false;
            }


            //Check whether the Item's CheckBox) is checked.
            if (checkbox.checked) {
                selectedItemsTexts += item.get_text() + ", ";
                selectedItemsValues += item.get_value() + ", ";
            }
        }
    }

    selectedItemsTexts = selectedItemsTexts.substring(0, selectedItemsTexts.length - 2);
    selectedItemsValues = selectedItemsValues.substring(0, selectedItemsValues.length - 2);

    if (isAllSelected) {
        selectedItemsTexts = "ALL";
    }
    //Set the text of the RadComboBox with the texts of the selected Items, separated by ','.

    if (selectedItemsTexts == "")
        selectedItemsTexts = "<Please Select>";


    combo.set_text(selectedItemsTexts);

}
//End Javascript

When the dropdownlist gets focus, we expand the dropdown list and change the focus to the first control in the list.

The key to this working is trapping the "tab" and the "down arrow" keys so that you can manipulate the behavior. Otherwise when the dropdown opens the "tab" key will go to the next item in the dropdown instead of going to the next control on page. When the user presses "tab", we give focus to the input element of the RadComboBox, close the dropdown, and send back "tab", when tab gets sent back, the form will tab to the next control on tha page. When the user presses the "down arrow" we just send back the "tab" key value back to the form, and it will go to the next item in the dropdown.

Hopefully this was helpful to someone.



No answers yet. Maybe you can help?

Tags
ComboBox
Asked by
instigator
Top achievements
Rank 1
Share this question
or