How to use the GridComboBox component

The GridComboBox class displays an editable text input and a button, that when triggered, renders the items from a data collection in a pop-up grid view.

⚠️ Beta Notice: This component is still quite new. Some APIs may go through minor changes in upcoming releases.

The Basics

Start by creating a GridComboBox control, and add it to the display list.

var gridComboBox = new GridComboBox();
addChild(gridComboBox);

Data provider and columns

To render some data in the grid view, pass in a collection that contains an object for each row.

gridComboBox.dataProvider = new ArrayCollection([
    { item: "Chicken breast", dept: "Meat", price: "5.90" },
    { item: "Bacon", dept: "Meat", price: "4.49" },
    { item: "2% Milk", dept: "Dairy", price: "2.49" },
    { item: "Butter", dept: "Dairy", price: "4.69" },
    { item: "Lettuce", dept: "Produce", price: "1.29" },
    { item: "Broccoli", dept: "Produce", price: "2.99" },
    { item: "Whole Wheat Bread", dept: "Bakery", price: "2.49" },
    { item: "English Muffins", dept: "Bakery", price: "2.99" }
]);

Set the itemToText() method to get the text from each item to display in the button (each column will have its own, separate function for text to display in cell renderers).

comboBox.itemToText = function(item:Dynamic):String {
    return item.text;
};

Next, define the columns in the grid view, so that it knows which fields from the data provider's items to display. One of the items from the data provider appears below.

{ item: "Broccoli", dept: "Produce", price: "2.99" },

The item has three fields, item, dept, and price. Create a separate GridViewColumn for each of the fields in the item, and pass them to the columns property.

gridComboBox.columns = new ArrayCollection([
    new GridViewColumn("Item", (data:Dynamic) -> data.item),
    new GridViewColumn("Department", (data:Dynamic) -> data.dept),
    new GridViewColumn("Unit Price", (data:Dynamic) -> data.price)
]);

The first parameter of the GridViewColumn is the text to display in each column header. The second parameter is passed to the itemToText() property, which is a function that returns the text to display in a cell renderer.

Items in the collection are not required to be anonymous structures, like { item: "Bacon", dept: "Meat", price: "4.49" } in the example above. Class instances are allowed too (and encouraged as a best practice; you should prefer classes over anonymous structures).

Selection

Add an event listener for Event.CHANGE to perform an action when the user selects a different item.

gridComboBox.addEventListener(Event.CHANGE, gridComboBox_changeHandler);

Check for the new value of the selectedItem property in the listener.

function gridComboBox_changeHandler(event:Event):Void {
    var gridComboBox = cast(event.currentTarget, GridComboBox);
    trace("GridComboBox selectedItem change: " + gridComboBox.selectedItem.text);
}

Alternatively, the value of the selectedIndex property references the index of the items in the grid view's collection, in the order that they were added.

function gridComboBox_changeHandler(event:Event):Void {
    var gridComboBox = cast(event.currentTarget, GridComboBox);
    trace("GridComboBox selectedIndex change: " + gridComboBox.selectedIndex);
}

Add or remove rows

To add a new row at the end, pass an object to the data provider's add() method.

var newRow = { item: "Gala Apple", dept: "Produce", price: "1.00" };
gridComboBox.dataProvider.add(newRow);

To add a new row at a specific position, pass an object to the data provider's addAt() method.

var newRow = { item: "Banana", dept: "Produce", price: "0.32" };
gridComboBox.dataProvider.addAt(newRow, 0);

In the example above, a new row is added to the beginning.

Similarly, to remove a row, call remove() or removeAt() on the collection.

gridComboBox.dataProvider.removeAt(0);

Cell renderers

A cell renderer is a Feathers UI component that displays one of the fields from a single row displayed in a GridView or GridComboBox component. In other words, the GridView displayed by a GridComboBox typically contains many cell renderers in a two-dimensional grid — with each one rendering a different field from each row in the collection.

Feathers UI provides a default ItemRenderer class, which can display data in many different ways that cover a variety of common use-cases. However, components like GridComboBox also support custom cell renderers, which allow developers to render the grid view's data in infinite unique ways.

Consider a collection of items with the following format.

{ item: "Gala Apple", dept: "Frozen", price: "3.99", icon: "https://example.com/img/pizza.png" }

While the default ItemRenderer class can easily display some text and an image, creating a custom cell renderer for this simple data will be a good learning exercise.

A custom cell renderer designed to display this data might use a Label to display one of the strings, and an AssetLoader to display the image. The following example creates a DisplayObjectRecycler which instantiates these components and adds them to a LayoutGroupItemRenderer — a special base class for custom cell renderers.

var recycler = DisplayObjectRecycler.withFunction(() -> {
    var cellRenderer = new LayoutGroupItemRenderer();

    var layout = new HorizontalLayout();
    layout.gap = 6.0;
    layout.paddingTop = 4.0;
    layout.paddingBottom = 4.0;
    layout.paddingLeft = 6.0;
    layout.paddingRight = 6.0;
    cellRenderer.layout = layout;

    var icon = new AssetLoader();
    icon.name = "loader";
    cellRenderer.addChild(icon);

    var label = new Label();
    label.name = "label";
    cellRenderer.addChild(label);

    return cellRenderer;
});

Developers are not required to use the LayoutGroupItemRenderer class. In fact, a custom cell renderer may be created from any OpenFL display object, including primitives like openfl.display.Sprite and all other Feathers UI components.

Both GridComboBox and GridViewColumn define cellRendererRecycler properties. On GridViewColumn, the cellRendererRecycler property may be used to customize the cell renderers in that specific column. On GridComboBox, the cellRendererRecycler property may be used to customize the default cell renderers used when a particular column doesn't have a specific cell renderer.

var column = new GridViewColumn("Item", (data:Dynamic) -> data.item);
column.cellRendererRecycler = recycler;

So far, the DisplayObjectRecycler creates the cell renderer, but it doesn't understand how to interpret the data yet. A custom update() method on the recycler can do that.

recycler.update = (cellRenderer:LayoutGroupItemRenderer, state:GridViewCellState) -> {
    var label = cast(cellRenderer.getChildByName("label"), Label);
    var loader = cast(cellRenderer.getChildByName("loader"), AssetLoader);

    label.text = state.text;
    loader.source = state.data.icon;
};

When the update() method is called, it receives the cell renderer and an GridViewCellState object. GridViewCellState has a number of useful properties.

In this case, the value of text is displayed by the Label, and the icon field from data (remember the example row from above, with item and icon fields) is displayed by the AssetLoader.

It's always a good practice to provide a reset() method to the DisplayObjectRecycler, which will clean up a custom cell renderer when it is no longer used by the GridComboBox.

recycler.reset = (cellRenderer:LayoutGroupItemRenderer, state:GridViewCellState) -> {
    var label = cast(cellRenderer.getChildByName("label"), Label);
    var loader = cast(cellRenderer.getChildByName("loader"), AssetLoader);

    label.text = "";
    loader.source = null;
};

Warning: A DisplayObjectRecycler without a reset() method could potentially cause memory leaks or other unexpected behavior, if the same data needs to be used again later.

Styles

A number of styles may be customized on the sub-components of a GridComboBox component, including styles on the button, the text input, and the grid view.

Button

The button in a GridComboBox component is of type Button. Its appearance may be customized globally in a theme, or it may be customized outside of a theme on an specific, individual GridComboBox.

See How to use the Button component for complete details about which styles are available for the button.

Style button globally

Use the GridComboBox.CHILD_VARIANT_BUTTON constant in a theme to provide a function that globally styles the buttons in all GridComboBox components.

styleProvider.setStyleFunction(
    Button,
    GridComboBox.CHILD_VARIANT_BUTTON,
    setGridComboBox_Button_Styles);

The function should use the following signature.

function setGridComboBox_Button_Styles(button:Button):Void {
    // ... set styles here
}

Style the button in a specific GridComboBox

The buttonFactory property may be used to customize the creation of an individual button.

gridComboBox.buttonFactory = () -> {
    var button = new Button();
    // ... set styles here
    return button;
};

TextInput

The text input in a ComboBox component is of type TextInput. Its appearance may be customized globally in a theme, or it may be customized outside of a theme on an specific, individual ComboBox.

See How to use the TextInput component for complete details about which styles are available for the text input.

Style text input globally

Use the ComboBox.CHILD_VARIANT_TEXT_INPUT constant in a theme to provide a function that globally styles the text inputs in all ComboBox components.

styleProvider.setStyleFunction(
    TextInput,
    ComboBox.CHILD_VARIANT_TEXT_INPUT,
    setComboBox_TextInput_Styles);

The function should use the following signature.

function setComboBox_TextInput_Styles(button:TextInput):Void {
    // ... set styles here
}

Style the text input in a specific ComboBox

The textInputFactory property may be used to customize the creation of an individual text input.

gridComboBox.textInputFactory = () -> {
    var input = new TextInput();
    // ... set styles here
    return input;
};

GridView

The grid view in a GridComboBox component is of type GridView. Its appearance may be customized globally in a theme, or it may be customized outside of a theme on an specific, individual GridComboBox.

See How to use the GridView component for complete details about which styles are available for the grid view.

Style grid view globally

Use the GridComboBox.CHILD_VARIANT_GRID_VIEW constant in a theme to provide a function that globally styles the grid views in all GridComboBox components.

styleProvider.setStyleFunction(
    GridView,
    GridComboBox.CHILD_VARIANT_GRID_VIEW,
    setGridComboBox_GridView_Styles);

The function should use the following signature.

function setGridComboBox_GridView_Styles(gridView:GridView):Void {
    // ... set styles here
}

Style the grid view in a specific GridComboBox

The gridViewFactory property may be used to customize the creation of an individual grid view.

gridComboBox.gridViewFactory = () -> {
    var gridView = new GridView();
    // ... set styles here
    return gridView;
};